﻿#include "cppapi.h"
#include "global.h"
#include "exprvalue.h"
#include "ExprVisitor.h"
//#include "../global/rcglobal.h"


#include <QDateTime>
#include <iostream>
#include <initializer_list>
#include <QRegularExpression>
#include <QThread>
#include <QDir>
#include <XLSheet.hpp>
#include <XLStyles.hpp>
#include <QTextCodec>
#include <QProcess>
#ifdef NDD_PIN_FUN
#include <qsciscintilla.h>
#include <Scintilla.h>
#endif
#include <QCoreApplication>

void initPinFunTab();
int pin_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx);

extern std::atomic<bool> shouldExit;

//函数哈希表
//函数方法，对应的cpp底层的函数
std::unordered_map<std::string, CPP_FUN_INFO*> *s_cppFunTab = nullptr; // 全局变量的符号表
#ifdef NDD_PIN_FUN
extern std::function<QsciScintilla* (QWidget*)> s_getCurEdit;
#endif
extern int s_exit_code;

#define SCE_UNIVERSAL_FOUND_STYLE_EXT5 21

//函数的类型
enum FUN_TYPE_ID
{
    STRUCT_MEMBER_FUN = 0, //成员函数，最常见的。
    PACKET_GLOBAL_FUN,//包全局函数
    EXPR_ALL_PACK_FUN,//所有包名都可用的方法。目前就是desc函数。
};

enum CPP_FUN_ID_INDEX
{
    //小于1000的就是有重复键的，不能只使用函数名，还需要使用前面的类型名
    birthTime_Fun = 1, //返回时间
    lastModified_Fun,
    lastRead_Fun,
    metadataChangeTime_Fun,

    absoluteFilePath_Fun, //返回字符串
    absolutePath_Fun,
    baseName_Fun,
    bundleName_Fun,
    canonicalFilePath_Fun,
    canonicalPath_Fun,
    completeBaseName_Fun,
    completeSuffix_Fun,
    fileName_Fun,
    filePath_Fun,
    owner_Fun,
    path_Fun,
    suffix_Fun,
    symLinkTarget_Fun,

    exists_Fun, //反之bool
    isDir_Fun,
    isExecutable_Fun,
    isFile_Fun,
    isHidden_Fun,
    isReadable_Fun,
    isRelative_Fun,
    isShortcut_Fun,
    isSymLink_Fun,
    isSymbolicLink_Fun,
    isWritable_Fun,
    childFiles_Fun,//下面的子文件，包括文件和文件夹

    //QFile文件操作
    moveToTrash_Fun,
    remove_Fun,
    copy_Fun,
    rename_Fun,
    dirRename_Fun,//文件夹改名
    wj_open_Fun,
    size_Fun,
    close_Fun,



    readAll_Fun, //readAll() : QByteArray
    read_Fun,  //QByteArray QIODevice::read(qint64 maxSize) //没法实现read(char*, qint64)，因为不支持char*
    read_line_Fun,
    write_Fun, //write(const QByteArray&) : qint64
    //writeMax_Fun,//writeData(const char*, qint64) : qint64
    seek_Fun, //bool QFileDevice::seek(qint64 pos)
    pos_Fun, //virtual qint64 pos() const override

    //目前的全局方法。
    currentPath_Fun,
    homePath_Fun,
    tempPath_Fun,
    isAbsolutePath_Fun,
    isRelativePath_Fun,
    setCurrent_Fun,
    toNativeSeparators_Fun,
    drives_Fun,
    pathExist_Fun,
    fileExist_Fun,

    //补充全局文件操作
    rmfile_Fun,//wj::全局操作
    wj_static_copy_Fun,//
    static_moveToTrash_Fun,//全局操作
    static_rename_Fun,
    static_symLinkTarget_Fun,
    static_rmdir_Fun,
    static_rmpath_Fun,
    static_mkdir_Fun,
    static_mkpath_Fun,
    static_cd_Fun,
    static_cdUp_Fun,
    static_open_Fun,
    static_pathJoin_Fun,
    static_getRegularFilePath_Fun,

    //调用目录的对象方法
rmdir_Fun,
rmpath_Fun,
mkdir_Fun,
mkpath_Fun,

//QDateTime的函数
currentDateTime_Fun,
now_Fun,
addDays_Fun,
addMSecs_Fun,
addMonths_Fun,
addSecs_Fun,
addYears_Fun,
date_Fun,
daysTo_Fun,
isValid_Fun,
isNull_Fun,
msecsTo_Fun,
offsetFromUtc_Fun,
secsTo_Fun,
setDate_Fun,
setMSecsSinceEpoch_Fun,
setOffsetFromUtc_Fun,
setSecsSinceEpoch_Fun,
setTime_Fun,
//setTimeSpec_Fun,
//setTimeZone_Fun,
time_Fun,
//timeSpec_Fun,
//timeZone_Fun,
//timeZoneAbbreviation_Fun,
toLocalTime_Fun,
toMSecsSinceEpoch_Fun,
toOffsetFromUtc_Fun,
toSecsSinceEpoch_Fun,
toString_Fun,
getDateString_Fun,
getTimeString_Fun,
//toTimeSpec_Fun,
//toTimeZone_Fun,
toUTC_Fun,
fromString_Fun,
msleep_Fun,
sleep_Fun,

//字符串内部函数
zfc_append_Fun,
zfc_at_Fun,
zfc_back_Fun,
zfc_front_Fun,
chop_Fun,
chopped_Fun,
zfc_clear_Fun,
zfc_size_Fun,
compare_Fun,
zfc_contains_Fun,
zfc_count_Fun,
endsWith_Fun,
startsWith_Fun,
zfc_indexOf_Fun,
zfc_lastIndexOf_Fun,
zfc_insert_Fun,
zfc_isEmpty_Fun,
isLower_Fun,
isUpper_Fun,
zfc_left_Fun,
zfc_right_Fun,
leftJustified_Fun,
rightJustified_Fun,
zfc_mid_Fun,
zfc_remove_Fun,
zfc_push_back_Fun,
zfc_push_front_Fun,
zfc_replace_Fun,
simplified_Fun,
zfc_split_Fun,
toBase64_Fun,

toDouble_Fun,
toFloat_Fun,
toHex_Fun,
toInt_Fun,
toLongLong_Fun,
toLower_Fun,
toUpper_Fun,
trimmed_Fun,
truncate_Fun,
setPosChar_Fun,//[]
zfc_transCode_Fun,
//静态函数
//zfc_setNum_Fun,
zfc_number_Fun,
zfc_fromBase64_Fun,
zfc_fromHex_Fun,
zfc_create_Fun,

zfc_fromDoubleHex_Fun,
zfc_fromIntHex_Fun,
zfc_reverse_Fun,//字符串反转
static_zfc_reverse_Fun,

    //zf char 方法
    zf_num_Fun,
    zf_hex_Fun,


checksum_Fun,
compress_Fun,
uncompress_Fun,

//list
lb_size_Fun,
lb_append_Fun,
lb_at_Fun,
lb_last_Fun,
lb_isEmpty_Fun,
lb_clear_Fun,
lb_insert_Fun,
lb_create_Fun,
lb_first_Fun,


lb_indexOf_Fun,
lb_lastIndexOf_Fun,
lb_mid_Fun,
lb_removeAt_Fun,
lb_takeAt_Fun,
lb_takeFirst_Fun,
lb_takeLast_Fun,
lb_swapItemsAt_Fun,
lb_reserve_Fun,
lb_copy_Fun,

lb_sort_Fun,
lb_sortStruct_Fun,

//map
zd_clear_Fun,
zd_size_Fun,
zd_isEmpty_Fun,
zd_contains_Fun,
zd_remove_Fun,
zd_keys_Fun,
zd_value_Fun,
zd_copy_Fun,

//excel
excel_create_Fun,
excel_open_Fun,
excel_save_Fun,
excel_saveAs_Fun,
excel_isOpen_Fun,
excel_close_Fun,

excel_addWorksheet_Fun,
excel_deleteWorksheet_Fun,
excel_listSheetNames_Fun,
excel_sheetExists_Fun,
excel_cloneSheet_Fun,
excel_sheetCount_Fun,

//excel_selectWorksheet_Fun,

excel_worksheet_Fun,
XLWorksheet_setCell_Fun,
XLWorksheet_cell_Fun,
XLWorksheet_rowCount_Fun,
XLWorksheet_columnCount_Fun,
XLWorksheet_setName_Fun,
XLWorksheet_name_Fun,
XLWorksheet_deleteRow_Fun,
XLWorksheet_setFormula_Fun,
XLWorksheet_formula_Fun,

// XLWorksheet_setRgbColor_Fun,
 //XLWorksheet_setRgbaColor_Fun,
 //XLWorksheet_setTabColor_Fun,

 //pin全局方法
    pin_exec_Fun,
    pin_exec_output_Fun,
    pin_desc_Fun,
    pin_line_Fun,
    //pin_funname_Fun,
    pin_fun_Fun,
    pin_yield_Fun,
    pin_exit_Fun,
    pin_getopt_Fun,

    //qstring
    qstring_toZfc_Fun,
    getCharList_Fun,
    qstr_fromZfc_Fun,
    qstr_at_Fun,
    qstr_size_Fun,

        //字符串内部函数
        qstr_append_Fun,
        qstr_back_Fun,
        qstr_front_Fun,
        qstr_chop_Fun,
        qstr_chopped_Fun,
        qstr_clear_Fun,
        qstr_compare_Fun,
        qstr_contains_Fun,
        qstr_count_Fun,
        qstr_endsWith_Fun,
        qstr_startsWith_Fun,
        qstr_indexOf_Fun,
        qstr_lastIndexOf_Fun,
        qstr_insert_Fun,
        qstr_isEmpty_Fun,
        qstr_isLower_Fun,
        qstr_isUpper_Fun,
        qstr_left_Fun,
        qstr_right_Fun,
        qstr_leftJustified_Fun,
        qstr_rightJustified_Fun,
        qstr_mid_Fun,
        qstr_remove_Fun,
        qstr_push_back_Fun,
        qstr_push_front_Fun,
        qstr_replace_Fun,
        qstr_simplified_Fun,
        qstr_split_Fun,


    qstr_toDouble_Fun,
    qstr_toFloat_Fun,
    qstr_toInt_Fun,
    qstr_toLongLong_Fun,
    qstr_toLower_Fun,
    qstr_toUpper_Fun,
    qstr_trimmed_Fun,
    qstr_truncate_Fun,
    qstr_setPosChar_Fun,//[]

        //静态函数
    qstr_number_Fun,


    //QChar
    qchar_unicode_Fun,
    qchar_isDigit_Fun,
    qchar_isLetter_Fun,
    qchar_isLetterOrNumber_Fun,
    qchar_isPrint_Fun,
    qchar_isLower_Fun,
    qchar_isUpper_Fun,
    qchar_number_Fun,

    //qregexp
    reg_match_Fun,
    reg_globalMatch_Fun,
    reg_captureCount_Fun,
    reg_errorString_Fun,
    reg_re_isValid_Fun,
    reg_setPatternOptions_Fun,
    ret_setPattern_Fun,

    reg_captured_Fun,
    reg_capturedStart_Fun,
    reg_capturedEnd_Fun,
    reg_capturedLength_Fun,
    reg_hasMatch_Fun,
    reg_isValid_Fun,
    reg_capturedTexts_Fun,
    reg_lastCapturedIndex_Fun,

    reg_hasNext_Fun,
    reg_next_Fun,
    reg_peekNext_Fun,

    //ndd
    ndd_getMainWin_Fun,
    ndd_newEditor_Fun,
    ndd_curEditFilePath_Fun,
    ndd_getCurEdit_Fun,
    ndd_getEdit_Fun,

    ndd_getText_Fun,
    ndd_setText_Fun,
    ndd_getTextRange_Fun,
    ndd_getLine_Fun,
    ndd_lineCount_Fun,
    ndd_setsel_Fun,
    ndd_gotoPos_Fun,
    ndd_gotoLine_Fun,
    ndd_setcurpos_Fun,
    ndd_setanchor_Fun,
    ndd_getcurpos_Fun,
    ndd_getanchor_Fun,
    ndd_selectall_Fun,

    ndd_posBefore_Fun,
    ndd_posAfter_Fun,

    ndd_setselstart_Fun,
    ndd_setselend_Fun,

    ndd_getselstart_Fun,
    ndd_getselend_Fun,

    ndd_setemptysel_Fun,
    ndd_lineFromPos_Fun,
    ndd_posFromLine_Fun,

    ndd_getLineEndPos_Fun,
    ndd_lineLength_Fun,
    ndd_getSelText_Fun,

    ndd_removeSelText_Fun,
    ndd_replaceSelText_Fun,
    ndd_insertAtPos_Fun,
    ndd_deleteRange_Fun,
    ndd_highLight_Fun,
    ndd_clear_highLight_Fun,
    ndd_clearAllHighLight_Fun,
    ndd_beginundo_Fun,
    ndd_endundo_Fun
};



//这里目前是qt5的逻辑。
//将指定编码的字符串转换到unicode
bool tranStrToUNICODE(CODE_ID code, const char* pText, int length, QString &out)
{
    if (length < 0)
    {
        return false;
    }

    QTextCodec::ConverterState state;
    QTextCodec *codec = nullptr;

    QByteArray textCodeName = getQtCodecNameById(code);
    if (textCodeName.isEmpty() || textCodeName == "unknown")
    {
        //对于其它非识别编码，统一转换为utf8。减去让用户选择的麻烦
        //这里其实是有问题的。先这样简单处理
        codec = QTextCodec::codecForName("UTF-8");
    }
    else
    {
        codec = QTextCodec::codecForName(textCodeName.data());
    }

    if (codec == nullptr)
    {
        return false;
    }

    //预留内存，避免内存重复二次分配
    out.reserve(length);

    out = codec->toUnicode((const char *)pText, length, &state);
    if (state.invalidChars > 0) {
        return false;
    }
    return true;
}

//这里是qt5的逻辑，如果是qt6还需要新增部分逻辑。
QTextCodec* getTextCodeByCode(CODE_ID dstCode)
{
    QTextCodec* pTranCode = nullptr;

    //如果编码是已知如下类型，则后续保存其它行时，不修改编码格式，继续按照原编码进行保存
    switch (dstCode)
    {
    case CODE_ID::UNICODE_BE:
    {
        pTranCode = QTextCodec::codecForName("UTF-16BE");
    }
    break;

    case  CODE_ID::UNICODE_LE:
    {
        pTranCode = QTextCodec::codecForName("UTF-16LE");
    }
    break;

    case CODE_ID::UTF8_BOM:
    {
        pTranCode = QTextCodec::codecForName("UTF-8");
    }
    break;

    case  CODE_ID::GBK:
    {
        pTranCode = QTextCodec::codecForName("GBK");
    }
    break;

    case  CODE_ID::BIG5:
    {
        pTranCode = QTextCodec::codecForName("BIG5-HKSCS");
    }
    break;

    case  CODE_ID::Shift_JIS:
    {
        pTranCode = QTextCodec::codecForName("Shift-JIS");
    }
    break;

        case  CODE_ID::EUC_JP:
        {
            pTranCode = QTextCodec::codecForName("EUC-JP");
        }
        break;

        case  CODE_ID::EUC_KR:
        {
            pTranCode = QTextCodec::codecForName("EUC-KR");
        }
        break;

        case  CODE_ID::KOI8_R:
        {
            pTranCode = QTextCodec::codecForName("KOI8-R");
        }
        break;

        case  CODE_ID::IBM866:
        {
            pTranCode = QTextCodec::codecForName("IBM 866");
        }
        break;

        case  CODE_ID::WINDOWS1250:
        {
            pTranCode = QTextCodec::codecForName("Windows-1250");
        }
        break;

    default:
        //对于其它非识别编码，统一转换为utf8。减去让用户选择的麻烦
        pTranCode = QTextCodec::codecForName("UTF-8");

    }
    return pTranCode;
}


QFileInfo * getFileInfoFromExpr(ExprValue* expr);

/*
//为了避免路径中\\不一样导致的查找不到问题，进行统一替换
QString getRegularFilePath(QString& path)
{
#ifdef _WIN32
    path = path.replace("/", "\\");
#else
    path = path.replace("\\", "/");
#endif

    return path;
}*/

std::unordered_map<std::string, CPP_FUN_INFO*>* getFileFunTab()
{
    return s_cppFunTab;
}

//初始化文件操作的库

static bool s_file_fun_sys_load = false;
static bool s_excel_fun_sys_load = false;
static bool s_date_fun_sys_load = false;
static bool s_string_fun_sys_load = false;
static bool s_list_fun_sys_load = false;
static bool s_map_fun_sys_load = false;
static bool s_pin_fun_sys_load = false;//pin全局包名内部方法
static bool s_qstring_fun_sys_load = false;
static bool s_qchar_fun_sys_load = false;
static bool s_ndd_fun_sys_load = false;
static bool s_regexp_sys_load = false;
static bool s_char_fun_sys_load = false;

void resetGlboalVar()
{
    s_file_fun_sys_load = false;
    s_excel_fun_sys_load = false;
    s_date_fun_sys_load = false;
    s_string_fun_sys_load = false;
    s_list_fun_sys_load = false;
    s_map_fun_sys_load = false;
    s_pin_fun_sys_load = false;//pin全局包名内部方法
    s_qstring_fun_sys_load = false;
    s_ndd_fun_sys_load = false;
    s_qchar_fun_sys_load = false;
    s_regexp_sys_load = false;
    s_char_fun_sys_load = false;
}

QFileInfo* getFileInfoFromExpr(ExprValue* expr)
{
    if (expr->value.vpoint != nullptr && expr->type == EXPR_FILE)
    {
        return ((FILE_VALUE_DATA*)(expr->value.vpoint))->pFileInfo;
    }

    return nullptr;
}


EXCEL_VALUE_DATA* getExcelInfoFromExpr(ExprValue* expr, std::string &fileName)
{
    if (expr->value.vpoint != nullptr && expr->type == EXPR_EXCEL)
    {
        fileName = ((EXCEL_VALUE_DATA*)(expr->value.vpoint))->excelFileName;
        return ((EXCEL_VALUE_DATA*)(expr->value.vpoint));
    }

    return nullptr;
}


//前面要做检查的好，保证是OpenXLSX::XLWorksheet类型，否则里面any_cast报告异常。
OpenXLSX::XLWorksheet getExcelWorkSheetInfoFromExpr(ExprValue* expr)
{
    if (expr->value.vpoint != nullptr && expr->type == EXPR_STRUCT)
    {

        STRUCT_VALUE_DATA* pData =  (STRUCT_VALUE_DATA*)expr->value.vpoint;
        return std::any_cast<OpenXLSX::XLWorksheet>(pData->pCppObj);
    }

    return OpenXLSX::XLWorksheet();
}

QFile* getQFileFromExpr(ExprValue* expr)
{
    if (expr->value.vpoint != nullptr && expr->type == EXPR_FILE)
    {
        if (nullptr == ((FILE_VALUE_DATA*)(expr->value.vpoint))->pFileInfo)
        {
            return nullptr;
        }

        QFile* pFile = ((FILE_VALUE_DATA*)(expr->value.vpoint))->pFile;
        //如果文件是空，则赋值一下，等于是延迟赋值

        if (pFile == nullptr)
        {
            QString filePath = ((FILE_VALUE_DATA*)(expr->value.vpoint))->pFileInfo->absoluteFilePath();

            getRegularFilePath(filePath);
            pFile = new QFile(filePath);
            ((FILE_VALUE_DATA*)(expr->value.vpoint))->pFile = pFile;

#ifdef PIN_MEM_REF
            newTime();
#endif
        }

        return pFile;
    }

    return nullptr;
}

QDateTime* getQDateTimeFromExpr(ExprValue* expr)
{
    if (expr->value.vpoint != nullptr && expr->type == EXPR_DATE)
    {
        return (QDateTime*)(expr->value.vpoint);
    }
    return nullptr;
}

std::vector<ExprValue*>* getListFromExpr(ExprValue* expr)
{
    if (expr->value.vpoint != nullptr && expr->type == EXPR_LIST)
    {
        return (std::vector<ExprValue*>*)(expr->value.vpoint);
    }
    return nullptr;
}

std::unordered_map<ExprValue, ExprValue*>* getMapFromExpr(ExprValue* expr)
{
    if (expr->value.vpoint != nullptr && expr->type == EXPR_MAP)
    {
        return (std::unordered_map<ExprValue, ExprValue*>*)(expr->value.vpoint);
    }
    return nullptr;
}

CallbackFun s_register_call_back_fun; //当前注册时使用的回调函数
unsigned short s_register_pack_id; //当前注册函数归属的包，比如EXEL_FILE EXPR_STRING等。


//isGlobalFun 是否是全局包函数，默认为0
CPP_FUN_INFO* register_cpp_fun(unsigned short funId, const std::string& funName, const std::initializer_list<int>& args,short fun_type=0 /*CallbackFun call_back_fun, unsigned short pack_id*/)
{
    if(args.size() == 0)
    {
        //无参函数
        CPP_FUN_INFO *pvalue = new CPP_FUN_INFO(funId, nullptr);
        pvalue->call_back_fun = s_register_call_back_fun;
        pvalue->owner_pack_id = s_register_pack_id;
        if(fun_type != 0)
        {
            pvalue->fun_type = fun_type;
        }

#ifdef PIN_MEM_REF
        newTime();
        if(s_cppFunTab->find(funName) != s_cppFunTab->end())
        {
            assert(false);
        }
#endif



#ifdef PIN_DEBUG
        if(s_cppFunTab->find(funName) != s_cppFunTab->end())
        {
            std::cout << u8"重复函数名" << funName;
        }
#endif
        s_cppFunTab->insert({funName,pvalue });

        return pvalue;
    }
    else
    {
        //有参函数
        std::vector<int>* paraList = new std::vector<int>(args.size());
#ifdef PIN_MEM_REF
        newTime();
#endif
        //判断最后一个是不是可选值。
        if (EXPR_INT_OPTION == *(args.end()-1))
        {
            //最后一个参数是可选INT值。
            const int* ptr = args.begin();

            int index = 0;
            for (index = 0; index < args.size() - 2; ++index)
            {
                paraList->operator[](index) = ptr[index];
            }

            //最后一个直接算INT即可
            paraList->operator[](index++) = (*(args.end() - 2));//加入可选默认值。
            paraList->operator[](index) = (EXPR_INT_OPTION);

        }
        else if (EXPR_PARA_DYNANIC == *(args.end() - 1))
        {
            //判断是不是重载函数系列的动态参数。如果是，则只检查最大最小。
            //int maxParaNum = *(args.end() - 2);
            //int minParaNum = *(args.end() - 3);

            //参数不能超过范围，后续要检查。
             //最后一个参数是动参 EXPR_PARA_DYNANIC值。
            const int* ptr = args.begin();

            int index = 0;
            for (index = 0; index < args.size() - 1; ++index)
            {
                paraList->operator[](index) = ptr[index];
            }

            //最后一个直接算INT即可
            paraList->operator[](index) = (EXPR_PARA_DYNANIC);
        }
        else
        {

            int index = 0;
            for (int value : args) {
                paraList->operator[](index) = value;
                ++index;
            }
        }

        CPP_FUN_INFO *pvalue = new CPP_FUN_INFO(funId, paraList);

#ifdef PIN_MEM_REF
        newTime();
        if(s_cppFunTab->find(funName) != s_cppFunTab->end())
        {
            assert(false);
        }
#endif
        pvalue->call_back_fun = s_register_call_back_fun;
        pvalue->owner_pack_id = s_register_pack_id;
        if(fun_type != 0)
        {
            pvalue->fun_type = fun_type;
        }

#ifdef DEBUG
        assert(s_cppFunTab->find(funName) == s_cppFunTab->end());
#endif // DEBUG

#ifdef PIN_DEBUG
        if(s_cppFunTab->find(funName) != s_cppFunTab->end())
        {
            std::cout << u8"重复函数名" << funName;
        }
#endif

        s_cppFunTab->insert({funName,pvalue });

        return pvalue;
    }
    return nullptr;
}

int excelInfo_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;
    std::string filePath;

    OpenXLSX::XLDocument* pXlsx = nullptr;

    try
    {
    switch (fun_info->fun_id)
    {
        case excel_create_Fun:
        case excel_open_Fun:
        {
            //先取出参数个数。
            int callParaNum = lastIndex;
            if (callParaNum == 0 || callParaNum == 1)
            {
                isNeedRetValue = false;

                ExprValue* obj = callFunStack->at(lastIndex);
                if (obj != nullptr)
                {


                    EXCEL_VALUE_DATA* pExcelData = getExcelInfoFromExpr(obj, filePath);
                    if (pExcelData != nullptr && pExcelData->pDoc != nullptr)
                    {
                        pXlsx = pExcelData->pDoc;

                        //0 个参数
                        if (callParaNum == 0)
                        {
                            if (filePath.empty())
                            {
                                hasError = 3;
                            }
                            else
                            {
                                QByteArray bytes = QByteArray::fromStdString(filePath);
                                if (!bytes.endsWith(".xlsx"))
                                {
                                    bytes.append(".xlsx");
                                }
                                filePath = bytes.toStdString();
                            }
                        }
                        else if (callParaNum == 1) // 1个参数
                        {

                            --lastIndex; //倒数第一个参数 filer
                            ExprValue* paraFile = callFunStack->at(lastIndex);

                            if (paraFile->type == EXPR_STRING && paraFile->value.vpoint != nullptr)
                            {
                                QByteArray* bytes = (QByteArray*)paraFile->value.vpoint;
                                if (bytes->isEmpty())
                                {
                                    QString msg = QString(u8"错误：行号 %1 语句 %2 Excel 名称为空，不能创建或打开空名称的Excel文件 ！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(filePath));
                                    AbortException(msg);
                                }
                                else
                                {
                                    if (!bytes->endsWith(".xlsx"))
                                    {
                                        bytes->append(".xlsx");
                                    }
                                    filePath = bytes->toStdString();
                                }
                            }
                        }

                        if (hasError == 0)
                        {

                            //如果崩溃，则会打印出这个错误。
                            SymNode* pInfo = new SymNode;
                            pInfo->type = TIPS_INFO;
                            pInfo->value.vpoint = new QString(QString(u8"行号 %1 语句%2 进入创建或打开 Excel %3 文件中,创建或打开 Excel文件异常！").arg(curLine).arg(curStatement).arg(QStr(filePath)));
#ifdef PIN_MEM_REF
                            newTime(2);
#endif
                            getPinSymTable()->append(pInfo);

                            if (fun_info->fun_id == excel_create_Fun)
                            {
                                QFileInfo fi(QString::fromStdString(filePath));
                                if (fi.exists())
                                {
                                    QString msg = QString(u8"警告：行号 %1 语句%2 Excel %3 文件已经存在，重新创建将清空旧文件！").arg(curLine).arg(curStatement).arg(QStr(filePath));
                                    std::cout << msg.toStdString() << std::endl;
                                }
                                //如果当前已经打开其它文件,则先把其它文件关闭。
                                if (pXlsx->isOpen())
                                {
                                    pXlsx->close();
                                }
                                pXlsx->create(filePath);
                            }
                            else if (fun_info->fun_id == excel_open_Fun)
                            {
                                //如果当前已经打开其它文件,则先把其它文件关闭。
                                if (pXlsx->isOpen())
                                {
                                    pXlsx->close();
                                }
                                pXlsx->open(filePath);
                            }

                            ((EXCEL_VALUE_DATA*)(obj->value.vpoint))->excelFileName = filePath;

                            //没问题则不会打印。
                            deleteCurScopeVar(pInfo);
                        }

                    }
                    else
                    {
                        hasError = 1;
                    }
                }
            }
            else
            {
                hasError = 2;
            }

        }
        break;

        case excel_save_Fun:
        case excel_saveAs_Fun:
        case excel_isOpen_Fun:
        case excel_close_Fun:
        case excel_addWorksheet_Fun:
        case excel_cloneSheet_Fun:
        case excel_sheetExists_Fun:
        case excel_sheetCount_Fun:
        case excel_deleteWorksheet_Fun:
        case excel_listSheetNames_Fun:
        //case excel_selectWorksheet_Fun:
        case excel_worksheet_Fun:

        {
            isNeedRetValue = false;

            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                EXCEL_VALUE_DATA* pExcelData = getExcelInfoFromExpr(obj, filePath);
                if (pExcelData != nullptr && pExcelData->pDoc != nullptr)
                {
                    pXlsx = pExcelData->pDoc;

                    switch (fun_info->fun_id)
                    {
                    case excel_save_Fun:
                        if (pXlsx->isOpen())
                        {
                            pXlsx->save();
                        }
                        break;

                    case excel_close_Fun:
                        if (pXlsx->isOpen())
                        {
                            pXlsx->save();
                            pXlsx->close();
                        }
                        break;

                    case excel_isOpen_Fun:
                    {
                        isNeedRetValue = true;
                        exprRet->type = EXPR_BOOL;
                        exprRet->value.vbool = pXlsx->isOpen();
                    }
                    break;

                    case excel_saveAs_Fun:
                    {
                        --lastIndex; //倒数第一个参数

                        ExprValue* paraFilePath = callFunStack->at(lastIndex);

                        if (pXlsx->isOpen())
                        {
                            QByteArray *bytes = (QByteArray*)paraFilePath->value.vpoint;
                            pXlsx->saveAs(bytes->toStdString());
                        }
                        else
                        {
                            hasError = 6;
                    }
                    }
                        break;

                    case excel_sheetCount_Fun:
                    {
                        isNeedRetValue = true;
                        exprRet->type = EXPR_INT;
                        OpenXLSX::XLWorkbook pBook = pXlsx->workbook();
                        if(pXlsx->isOpen())
                        {
                        exprRet->value.vint = pBook.sheetCount();
                    }
                        else
                        {
                            hasError = 6;
                        }
                    }
                        break;

                    case excel_addWorksheet_Fun:
                    case excel_deleteWorksheet_Fun:
                    case excel_sheetExists_Fun:
                    case excel_cloneSheet_Fun:

                    {
                        --lastIndex; //倒数第一个参数

                        ExprValue* paraSheetName = callFunStack->at(lastIndex);

                        if (pXlsx->isOpen())
                        {
                            QByteArray *bytes = (QByteArray*)paraSheetName->value.vpoint;
                            if(bytes!=nullptr && !bytes->isEmpty())
                            {
                                OpenXLSX::XLWorkbook pBook = pXlsx->workbook();
                                //pExcelData->workBook = pBook;

                                switch(fun_info->fun_id)
                                {

                                case excel_addWorksheet_Fun:
                                    {

                                        //是否存在
                                        if(pBook.sheetExists(bytes->toStdString()))
                                        {
                                            QString msg = QString(u8"警告：行号 %1 语句 %2 新增sheet %3 跳过执行，因为sheet %3 已经存在！")
                                                              .arg(curLine).arg(curStatement).arg(QStr(bytes->toStdString()));
                                            std::cout << msg.toStdString() << std::endl;
                                        }
                                        else
                                        {
                                            pBook.addWorksheet(bytes->toStdString());
                                            pXlsx->save();
                                        }
                                    }
                                break;

                                case excel_deleteWorksheet_Fun:
                                    {
                                        //是否存在
                                        if(!pBook.sheetExists(bytes->toStdString()))
                                        {
                                            QString msg = QString(u8"警告：行号 %1 语句 %2 删除sheet %3 跳过执行，因为sheet %3 本来就不存在！")
                                                              .arg(curLine).arg(curStatement).arg(QStr(bytes->toStdString()));
                                            std::cout << msg.toStdString() << std::endl;
                                        }
                                        else
                                        {
                                            pBook.deleteSheet(bytes->toStdString());
                                            pXlsx->save();
                                        }
                                    }
                                break;

                                case excel_sheetExists_Fun:
                                    {
                                        isNeedRetValue = true;
                                        exprRet->type = EXPR_BOOL;
                                        exprRet->value.vbool = pBook.sheetExists(bytes->toStdString());
                                    }
                                break;

                                case excel_cloneSheet_Fun:
                                    {
                                        --lastIndex; //倒数第2个参数

                                        ExprValue* paraSrcName = callFunStack->at(lastIndex);
                                        QByteArray *srcBytes = (QByteArray*)paraSrcName->value.vpoint;

                                        //目标是否存在，不存在才行。
                                        if(pBook.sheetExists(bytes->toStdString()))
                                        {
                                            QString msg = QString(u8"警告：行号 %1 语句 %2 克隆表页%3 跳过执行，因为表页 %3 已经存在！")
                                                              .arg(curLine).arg(curStatement).arg(QStr(bytes->toStdString()));
                                            std::cout << msg.toStdString() << std::endl;
                                        }
                                        else
                                        {
                                            pBook.cloneSheet(srcBytes->toStdString(), bytes->toStdString());
                                            pXlsx->save();
                                        }

                                    }
                                break;
                                }


                            }
                            else
                            {
                                hasError = 5;
                            }
                        }
                        else
                        {
                            hasError = 6;
                        }
                    }
                    break;

                    case excel_listSheetNames_Fun:
                    {
                        isNeedRetValue = true;
                        if (pXlsx->isOpen())
                        {

                            OpenXLSX::XLWorkbook pBook = pXlsx->workbook();
                            std::vector<std::string> ret = pBook.worksheetNames();

                            exprRet->type = EXPR_LIST;
                            std::vector<ExprValue*>* pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>(ret.size());
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            exprRet->value.vpoint = pData;
                            addListMapRefNum(pData);

                            for(int i=0,s = ret.size(); i<s; ++i)
                            {
                                ExprValue* expr = new ExprValue;
                                expr->type = EXPR_STRING;
                                expr->value.vpoint = new QByteArray(QByteArray::fromStdString(ret.at(i)));
                                pData->operator [](i) = expr;
#ifdef PIN_MEM_REF
                            newTime(2);
#endif
                            }

                        }
                        else
                        {
                            hasError = 6;
                        }
                    }
                    break;

                    case excel_worksheet_Fun:
                    {
                        isNeedRetValue = true;
                        if (pXlsx->isOpen())
                        {
                            //先取出参数个数。
                            int callParaNum = lastIndex;

                            if(callParaNum == 1)
                            {
                                exprRet->type = EXPR_STRUCT;

                                STRUCT_VALUE_DATA* pData =  new STRUCT_VALUE_DATA();


                                std::vector<ExprValue*>* pExprRet = new std::vector<ExprValue*>(2);
                                pData->pValue = pExprRet;

                                (*pExprRet)[0] = obj->deepCopy2();

                                pData->structType = "XLWorksheet";
                                pData->structTypeId = XLWorksheet_Struct_ID;

                                exprRet->value.vpoint = pData;
    #ifdef PIN_MEM_REF
                                newTime(2);
    #endif
                                --lastIndex; //倒数第一个参数
                                ExprValue* para1 = callFunStack->at(lastIndex);

                                /*if(para1->type == EXPR_INT)
                                {

                                    OpenXLSX::XLWorkbook pBook = pXlsx->workbook();

                                    int sc = pBook.sheetCount();
                                    if(para1->value.vint <= 0 || para1->value.vint > sc)
                                    {
                                        QString msg = QString(u8"错误：行号 %1 语句 %2 当前Excel %3 有%4 张sheet, 访问的sheet下标 %5 越界！")
                                                          .arg(curLine).arg(curStatement).arg(QStr(filePath)).arg(pBook.sheetCount()).arg(para1->value.vint);
                                        AbortException(msg);
                                    }
                                    else
                                    {
                                        pData->pCppObj = pBook.worksheet(0);
                                    }
                                }
                                else */if(para1->type == EXPR_STRING)
                                {
                                    OpenXLSX::XLWorkbook pBook = pXlsx->workbook();

                                    std::string sname = ((QByteArray*)para1->value.vpoint)->toStdString();

                                    if(!pBook.sheetExists(sname))
                                    {
                                        QString msg = QString(u8"错误：行号 %1 语句 %2 获取表页 %3 执行失败，因为表页 %3 本来就不存在！")
                                                          .arg(curLine).arg(curStatement).arg(QStr(sname));
                                        std::cerr << msg.toStdString() << std::endl;

                                        //还是退出算了，避免获取到不存在的页面，后续继续操作崩溃
                                        AbortException(msg);

                                        (*pExprRet)[1] =  ExprValue("").shallowMoveCopy();
                                        pData->pCppObj = -1;
                                    }
                                    else
                                    {

                                        pData->pCppObj = pBook.worksheet(sname);

                                        (*pExprRet)[1] =  para1->deepCopy2();
                                    }
                                }
                                else
                                {
                                    hasError = 2;
                                }
                            }
                            else
                            {
                                hasError = 2;
                            }
                        }
                        else
                        {
                            hasError = 6;
                        }

                    }
                    break;



                    }
                }
            }
        }
        break;


        case XLWorksheet_setFormula_Fun:
        case XLWorksheet_setCell_Fun:
        {
            isNeedRetValue = false;

            //先取出参数个数。
            int callParaNum = lastIndex;

            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                OpenXLSX::XLWorksheet ws = getExcelWorkSheetInfoFromExpr(obj);

                hasError = 8;
                if(callParaNum == 2)
                {
                    --lastIndex; //倒数第一个参数
                    ExprValue* para2 = callFunStack->at(lastIndex);

                    --lastIndex; //倒数第一个参数
                    ExprValue* para1 = callFunStack->at(lastIndex);

                    if(para1->type == EXPR_STRING)
                    {
                        if (fun_info->fun_id == XLWorksheet_setCell_Fun)
                        {
                            hasError = 0;

                            switch (para2->type)
                            {
                            case EXPR_INT:
                            {
                                ws.cell(para1->getString()).value() = para2->value.vint;
                            }
                            break;
                            case EXPR_INT64:
                            {
                                ws.cell(para1->getString()).value() = para2->value.vint64;
                            }
                            break;
                            case EXPR_FLOAT:
                            {
                                ws.cell(para1->getString()).value() = para2->value.vfloat;
                            }
                            break;
                            case EXPR_STRING:
                            {
                                ws.cell(para1->getString()).value() = para2->getString();
                            }
                            break;

                            }
                        }
                        else if (fun_info->fun_id == XLWorksheet_setFormula_Fun)
                        {
                            //公式只能是字符串格式。
                            if (para2->type == EXPR_STRING)
                            {
                                hasError = 0;
                                ws.cell(para1->getString()).formula() = para2->getString();
                            }
                        }
                    }
                }
                else if(callParaNum == 3)
                {
                    --lastIndex; //倒数第1个参数
                    ExprValue* para3 = callFunStack->at(lastIndex);

                    --lastIndex; //倒数第2个参数
                    ExprValue* para2 = callFunStack->at(lastIndex);

                    --lastIndex; //倒数第3个参数
                    ExprValue* para1 = callFunStack->at(lastIndex);

                    if(para1->type == EXPR_INT && para2->type == EXPR_INT)
                    {
                        if (fun_info->fun_id == XLWorksheet_setCell_Fun)
                        {

                            hasError = 0;

                            switch (para3->type)
                            {
                                case EXPR_INT:
                                {
                                    ws.cell(para1->value.vint, para2->value.vint).value() = para3->value.vint;
                                }
                                break;
                                case EXPR_INT64:
                                {
                                    ws.cell(para1->value.vint, para2->value.vint).value() = para3->value.vint64;
                                }
                                break;
                                case EXPR_FLOAT:
                                {
                                    ws.cell(para1->value.vint, para2->value.vint).value() = para3->value.vfloat;
                                }
                                break;
                                case EXPR_STRING:
                                {
                                    ws.cell(para1->value.vint, para2->value.vint).value() = para3->getString();
                                }
                                break;

                            }
                        }
                        else if (fun_info->fun_id == XLWorksheet_setFormula_Fun)
                        {
                            //公式只能是字符串格式。
                            if (para3->type == EXPR_STRING)
                            {
                                hasError = 0;
                                ws.cell(para1->value.vint, para2->value.vint).formula() = para3->getString();
                            }
                        }
                    }
                }


            }
        }
        break;

        case XLWorksheet_cell_Fun:
        case XLWorksheet_rowCount_Fun:
        case XLWorksheet_columnCount_Fun:
        case XLWorksheet_setName_Fun:
        case XLWorksheet_name_Fun:
        case XLWorksheet_deleteRow_Fun:
        case XLWorksheet_formula_Fun:
        //case XLWorksheet_setRgbColor_Fun:
        {
            isNeedRetValue = true;

            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                OpenXLSX::XLWorksheet ws = getExcelWorkSheetInfoFromExpr(obj);

                switch(fun_info->fun_id)
                {

                    case XLWorksheet_cell_Fun:
                    case XLWorksheet_formula_Fun:
                    {


                    //先取出参数个数。
                    int callParaNum = lastIndex;
                    hasError = 8;
                    if(callParaNum == 1)
                    {
                        --lastIndex; //倒数第一个参数
                        ExprValue* para1 = callFunStack->at(lastIndex);

                        if(para1->type == EXPR_STRING)
                        {
                            if (fun_info->fun_id == XLWorksheet_cell_Fun)
                            {
                                hasError = 0;
                                switch (ws.cell(para1->getString()).value().type())
                                {
                                case OpenXLSX::XLValueType::Integer:
                                {
                                    exprRet->type = EXPR_INT64;
                                    exprRet->value.vint64 = ws.cell(para1->getString()).value().get<int64_t>();
                                }
                                break;

                                case OpenXLSX::XLValueType::Float:
                                {
                                    exprRet->type = EXPR_FLOAT;
                                    exprRet->value.vfloat = ws.cell(para1->getString()).value().get<double>();
                                }
                                break;

                                case OpenXLSX::XLValueType::String:
                                {
                                    exprRet->type = EXPR_STRING;

                                    exprRet->value.vpoint = new QByteArray(QByteArray::fromStdString(ws.cell(para1->getString()).value().get<std::string>()));
#ifdef PIN_MEM_REF
                                    newTime();
#endif
                                }
                                break;

                                case OpenXLSX::XLValueType::Boolean:
                                {
                                    exprRet->type = EXPR_BOOL;
                                    exprRet->value.vbool = ws.cell(para1->getString()).value().get<bool>();

                                }
                                break;

                                default:
                                {
                                    exprRet->type = EXPR_INT;
                                    exprRet->value.vint = 0;

                                }
                                break;
                                }
                            }
                            else if (fun_info->fun_id == XLWorksheet_formula_Fun)
                            {
                                exprRet->type = EXPR_STRING;
                                hasError = 0;
                                if (ws.cell(para1->getString()).hasFormula())
                                {
                                    std::string flaString = ws.cell(para1->getString()).formula();
                                    exprRet->setString(flaString);
                                }
                                else
                                {
                                    //没有返回空字符串
                                    exprRet->setString("");
                                }
                            }
                        }
                    }
                    else if(callParaNum == 2)
                    {
                        --lastIndex; //倒数第一个参数
                        ExprValue* para2 = callFunStack->at(lastIndex);

                        --lastIndex; //倒数第一个参数
                        ExprValue* para1 = callFunStack->at(lastIndex);

                        if(para1->type == EXPR_INT && para2->type == EXPR_INT)
                        {
                            if (fun_info->fun_id == XLWorksheet_cell_Fun)
                            {
                                hasError = 0;
                                switch (ws.cell(para1->value.vint, para2->value.vint).value().type())
                                {
                                    case OpenXLSX::XLValueType::Integer:
                                    {
                                        exprRet->type = EXPR_INT64;
                                        exprRet->value.vint64 = ws.cell(para1->value.vint, para2->value.vint).value().get<int64_t>();
                                    }
                                    break;

                                    case OpenXLSX::XLValueType::Float:
                                    {
                                        exprRet->type = EXPR_FLOAT;
                                        exprRet->value.vfloat = ws.cell(para1->value.vint, para2->value.vint).value().get<double>();
                                    }
                                    break;

                                    case OpenXLSX::XLValueType::String:
                                    {
                                        exprRet->type = EXPR_STRING;

                                        exprRet->value.vpoint = new QByteArray(QByteArray::fromStdString(ws.cell(para1->value.vint, para2->value.vint).value().get<std::string>()));
    #ifdef PIN_MEM_REF
                                        newTime();
    #endif
                                    }
                                    break;

                                    case OpenXLSX::XLValueType::Boolean:
                                    {
                                        exprRet->type = EXPR_BOOL;
                                        exprRet->value.vbool = ws.cell(para1->value.vint, para2->value.vint).value().get<bool>();

                                    }
                                    break;

                                    default:
                                    {
                                        exprRet->type = EXPR_INT;
                                        exprRet->value.vint = 0;

                                    }
                                    break;
                                }
                            }
                            else if (fun_info->fun_id == XLWorksheet_formula_Fun)
                            {
                                exprRet->type = EXPR_STRING;
                                hasError = 0;
                                if (ws.cell(para1->value.vint, para2->value.vint).hasFormula())
                                {
                                    std::string flaString = ws.cell(para1->value.vint, para2->value.vint).formula();
                                    exprRet->setString(flaString);
                                }
                                else
                                {
                                    //没有返回空字符串
                                    exprRet->setString("");
                                }
                            }
                        }

                    }
                    }
                    break;

                    case XLWorksheet_rowCount_Fun:
                    {
                        exprRet->type = EXPR_INT;
                        exprRet->value.vint = ws.rowCount();

                    }
                    break;

                    case XLWorksheet_columnCount_Fun:
                    {
                        exprRet->type = EXPR_INT;
                        exprRet->value.vint = ws.columnCount();
                    }
                    break;

                    case XLWorksheet_setName_Fun:
                    {
                        isNeedRetValue = false;
                        --lastIndex; //倒数第一个参数
                        ExprValue* paraNewSheetName = callFunStack->at(lastIndex);
                        QByteArray *bytes = (QByteArray*)paraNewSheetName->value.vpoint;

                        ws.setName(bytes->toStdString());
                    }
                    break;

                    case XLWorksheet_name_Fun:
                    {
                        exprRet->type = EXPR_STRING;
                        exprRet->value.vpoint = new QByteArray(QByteArray::fromStdString(ws.name()));
#ifdef PIN_MEM_REF
                        newTime();
#endif
                    }
                    break;

                    case XLWorksheet_deleteRow_Fun:
                    {
                        --lastIndex; //倒数第一个参数
                        ExprValue* para1 = callFunStack->at(lastIndex);

                        exprRet->type = EXPR_BOOL;

                        exprRet->value.vbool = ws.deleteRow(para1->value.vint);


                    }
                    break;

                    /*
                    case XLWorksheet_setRgbColor_Fun:
                    {

                        isNeedRetValue = false;


                        --lastIndex; //倒数第一个参数
                        ExprValue* para3 = callFunStack->at(lastIndex);

                        --lastIndex; //倒数第一个参数
                        ExprValue* para2 = callFunStack->at(lastIndex);

                        --lastIndex; //倒数第一个参数
                        ExprValue* para1 = callFunStack->at(lastIndex);

                        OpenXLSX::XLColor color(para1->value.vint,para2->value.vint,para3->value.vint);

                        ws.setColor(color);

                    }
                    break;*/
                }

            }
        }
        break;

        /*
        case XLWorksheet_setTabColor_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                OpenXLSX::XLWorksheet ws = getExcelWorkSheetInfoFromExpr(obj);

                STRUCT_VALUE_DATA* pData =  (STRUCT_VALUE_DATA*)obj->value.vpoint;
                std::vector<ExprValue*>* pSheetStructVec = pData->pValue;

                ExprValue* pExcel = pSheetStructVec->operator [](0);

                OpenXLSX::XLDocument* pXlsx = nullptr;
                EXCEL_VALUE_DATA* pExcelData = getExcelInfoFromExpr(pExcel, filePath);
                if (pExcelData != nullptr && pExcelData->pDoc != nullptr)
                {
                    pXlsx = pExcelData->pDoc;
                }

                OpenXLSX::XLWorkbook book = pXlsx->workbook();
            }
        }
        break;*/
    }
    }
    catch (const std::runtime_error& e)
    {
        std::cerr << u8"捕获运行异常错误: \n" << e.what() << std::endl;

        if(fun_info->fun_id == XLWorksheet_setCell_Fun)
        {
            ExprValue* para1 = callFunStack->at(lastIndex);

            QString msg = QString(u8"您要操作的Excel 位置是 %1, 该位置是否存在？比如A1-Z1,注意下标 0 位置是不存在的！").arg(QStr(para1->getString()));
            std::cout << msg.toStdString() << std::endl;
        }
        hasError = 7;
    }

    if (hasError != 0)
    {

        ExprValue* funNameExpr = callFunStack->last();

        int lastIndex = callFunStack->size() - 1;
        ExprValue* obj = callFunStack->at(--lastIndex);

        std::string funName = ((QByteArray*)funNameExpr->value.vpoint)->toStdString();

        switch (hasError)
        {
            case 1:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 变量 %3 不是Excel 类型！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName));
                AbortException(msg);
            }
            break;
            case 2:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 参数个数无法匹配！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(funName));
                AbortException(msg);
            }
            break;
            case 3:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 初始化时没有给Excel 文件名称，调用%3 需要给出新建Excel文件的参数！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(funName));
                AbortException(msg);
            }
            break;
            case 4:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 Excel 变量 %3 已经打开文件 %4，不能直接创建或打开其他文件，请先关闭后再创建或打开其他Excel文件！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(filePath));
                AbortException(msg);
            }
            break;
            case 5:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 参数值是空字符串，无法创建Excel 标签页！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(funName));
                AbortException(msg);
            }
            break;
            case 6:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 Excel 变量 %3 没有先执行打开表格操作, 操作 %4 无法执行，请先创建或打开Excel文件！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(funName));
                AbortException(msg);
            }
            break;
            case 7:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 变量 %3 调用Excel 函数 %4 发生异常，请检查！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(funName));
                AbortException(msg);
            }
            case 8:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 变量或表达式 %3 调用函数 %4 参数无法匹配,请检查参数个数或格式！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(funName));
                AbortException(msg);
            }

            break;

        }
    }

    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }

    return hasError;
}

//QFileInfo 的函数全部写在一起。前面已经检查过参数的匹配问题。
int qfileInfo_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    switch (fun_info->fun_id)
    {
        case birthTime_Fun:
        case lastModified_Fun:
        case lastRead_Fun:
        case metadataChangeTime_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                QFileInfo* pFi = getFileInfoFromExpr(obj);
                if (pFi != nullptr)
                {
                    QDateTime ret;

                    switch (fun_info->fun_id)
                    {
                    case birthTime_Fun:
                    {
                        ret = pFi->birthTime();
                    }
                    break;
                    case lastModified_Fun:
                    {
                        ret = pFi->lastModified();
                    }
                    break;
                    case lastRead_Fun:
                    {
                        ret = pFi->lastRead();
                    }
                    break;
                    case metadataChangeTime_Fun:
                    {
                        ret = pFi->metadataChangeTime();
                    }
                    break;
                    }
                    //使用栈返回
                    ExprValue* exprRet = new ExprValue();
                    exprRet->type = EXPR_DATE;

                    exprRet->value.vpoint = new QDateTime(ret);
                    callFunStack->push_back(exprRet);
    #ifdef PIN_MEM_REF
                    newTime(2);
    #endif
                }
                else
                {
                    hasError = 1;

                }
            }
        }
        break;

        case  absoluteFilePath_Fun:
        case  absolutePath_Fun:
        case  baseName_Fun:
        case  bundleName_Fun:
        case  canonicalFilePath_Fun:
        case  canonicalPath_Fun:
        case  completeBaseName_Fun:
        case  completeSuffix_Fun:
        case  fileName_Fun:
        case  filePath_Fun:
        case  owner_Fun:
        case  path_Fun:
        case  suffix_Fun:
        case  symLinkTarget_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                QFileInfo* pFi = getFileInfoFromExpr(obj);
                if (pFi != nullptr)
                {
                    QString ret;

                    switch (fun_info->fun_id)
                    {
                    case  absoluteFilePath_Fun:
                    {
                        ret = pFi->absoluteFilePath();
                    }
                    break;
                    case  absolutePath_Fun:
                    {
                        ret = pFi->absolutePath();
                    }
                    break;
                    case  baseName_Fun:
                    {
                        ret = pFi->baseName();
                    }
                    break;
                    case  bundleName_Fun:
                    {
                        ret = pFi->bundleName();
                    }
                    break;

                    case  canonicalFilePath_Fun:
                    {
                        ret = pFi->canonicalFilePath();
                    }
                    break;

                    case  canonicalPath_Fun:
                    {
                        ret = pFi->canonicalPath();
                    }
                    break;

                    case  completeBaseName_Fun:
                    {
                        ret = pFi->completeBaseName();
                    }
                    break;

                    case  completeSuffix_Fun:
                    {
                        ret = pFi->completeSuffix();
                    }
                    break;

                    case  fileName_Fun:
                    {
                        ret = pFi->fileName();
                    }
                    break;

                    case  filePath_Fun:
                    {
                        ret = pFi->filePath();
                    }
                    break;
                    case  owner_Fun:
                    {
                        ret = pFi->owner();
                    }
                    break;
                    case  path_Fun:
                    {
                        ret = pFi->path();
                    }
                    break;
                    case  suffix_Fun:
                    {
                        ret = pFi->suffix();
                    }
                    break;
                    case  symLinkTarget_Fun:
                    {
                        ret = pFi->symLinkTarget();
                    }
                    break;

                    }
                    //使用栈返回
                    ExprValue* exprRet = new ExprValue();
                    exprRet->type = EXPR_STRING;

                    exprRet->value.vpoint = new QByteArray(ret.toUtf8());
                    callFunStack->push_back(exprRet);
        #ifdef PIN_MEM_REF
                    newTime(2);
        #endif
                }
                else
                {
                    hasError = 1;
                }
            }
        }
        break;
    }

    if (hasError != 0)
    {
        int lastIndex = callFunStack->size() - 1;
        ExprValue* obj = callFunStack->at(--lastIndex);

        if (1 == hasError)
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2 变量 %3 不是有效的文件类型或是 kong 类型文件！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName));
            AbortException(msg);
        }
        else if (2 == hasError)
        {
            ExprValue* funName = callFunStack->last();
            std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

            QString msg = QString(u8"错误：函数 %1 语句 %2 变量 %3 调用成员函数 %4 参数错误，缺少必要的参数，请检查函数参数个数是否正确！").arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(name));
            AbortException(msg);
        }
    }

    return hasError;
}


bool openFileFun(QFile* pFile, QString& openMode, ExprValue* exprRet, PinParser::RealCallFunContext* & ctx)
{
    //r w rw a t
    QIODevice::OpenMode mode = QIODevice::NotOpen;

    if (openMode.contains("r"))//读
    {
        mode = QIODevice::ReadOnly;
    }

    if (openMode.contains("w"))//写
    {
        mode |= QIODevice::WriteOnly;
    }

    if (openMode.contains("a"))//追加
    {
        mode |= QIODevice::Append;
    }

    if (openMode.contains("t"))//文本模式
    {
        mode |= QIODevice::Text;
    }

    if (openMode.contains("c"))//清空模式
    {
        mode |= QIODevice::Truncate;
    }

    int modeMatch = 0;

    if (openMode.contains("n"))//新建文件
    {
        mode |= QIODevice::NewOnly;

        if (pFile->exists())
        {
            //文件存在。
            exprRet->value.vbool = false;
            QString errInfo = QString(u8"错误：行号 %1 文件%2 已经存在！模式 n 下打开文件必须是一个不存在的文件！").arg(curLine).arg(pFile->fileName());
            //std::cout << errInfo.toStdString() << std::endl;
            //return 0;
            AbortException(errInfo);
        }
        modeMatch = 1;
    }

    if (openMode.contains("e"))//必须存在
    {
        if (modeMatch == 1)
        {
            //不能和n 共存。
            exprRet->value.vbool = false;
            QString errInfo = QString(u8"错误：行号 %1 打开文件%2 模式错误。模式 e 和 n 无法同时存在 ！").arg(curLine).arg(pFile->fileName());
            //std::cout << errInfo.toStdString() << std::endl;
            //return 0;
            AbortException(errInfo);
        }
        mode |= QIODevice::ExistingOnly;

        if (!pFile->exists())
        {
            //文件不存在。
            exprRet->value.vbool = false;
            QString errInfo = QString(u8"错误：行号 %1 文件%2 不存在！模式 e 下打开文件必须存在该文件！").arg(curLine).arg(pFile->fileName());
            //std::cout << errInfo.toStdString() << std::endl;
            //return 0;
            AbortException(errInfo);
        }
    }

    exprRet->value.vbool = pFile->open(mode);

    if (!exprRet->value.vbool)
    {
        //这里不退出，只打印打开失败。
        QString errInfo = QString(u8"错误：行号 %1 语句 %2 文件 %3 打开失败！%4").arg(curLine).arg(curStatement).arg(pFile->fileName()).arg(pFile->errorString());
        std::cout << errInfo.toStdString() << std::endl;
        //AbortException(errInfo);
    }

    return exprRet->value.vbool;
}

int qfile_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    ExprValue* funName = callFunStack->last();

    std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

    //取出函数对象,在倒数第二个。
    --lastIndex;

    int curParaIndex = 0;
    bool isNeedRetValue = true;

    //使用栈返回
    ExprValue* exprRet = new ExprValue();
#ifdef PIN_MEM_REF
    newTime();
#endif

    switch (fun_info->fun_id)
    {
        //静态函数，返回下面的子文件，一个列表。
        case childFiles_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj->type == EXPR_GLOBAL_PACKNAME)
            {
                if (EXPR_FILE == obj->value.vpacktype)
                {
                    //先取出参数个数。
                    int callParaNum = lastIndex;


                    QString dirPath;
                    //默认不要快捷方式，发现快捷方式可能导致循环进入。
                    QDir::Filters filter = QDir::AllEntries | QDir::NoDotAndDotDot | QDir::NoSymLinks;
                    QDir::SortFlags sortFlags = QDir::NoSort;

                    //1个参数,只有目录
                    if (1 == callParaNum)
                    {
                        --lastIndex; //倒数第一个参数

                        ExprValue* paraDir = callFunStack->at(lastIndex);
                        if (paraDir->type == EXPR_STRING)
                        {
                            dirPath = QString(*(QByteArray*)paraDir->value.vpoint);
                        }
                    }
                    else if (2 == callParaNum)
                    {

                        --lastIndex; //倒数第一个参数 filer
                        ExprValue* paraFilter = callFunStack->at(lastIndex);

                        --lastIndex; //倒数第2个参数
                        ExprValue* paraDir = callFunStack->at(lastIndex);

                        if ((paraFilter->type == EXPR_INT || paraFilter->type == EXPR_INT64) && paraDir->type == EXPR_STRING)
                        {
                            dirPath = QString(*(QByteArray*)paraDir->value.vpoint);
                            filter |= (QDir::Filters)paraFilter->value.vint;
                        }
                    }
                    else if (3 == callParaNum)
                    {
                        --lastIndex; //倒数第一个参数排序
                        ExprValue* paraSort = callFunStack->at(lastIndex);

                        --lastIndex; //倒数第一个参数 filer
                        ExprValue* paraFilter = callFunStack->at(lastIndex);

                        --lastIndex; //倒数第2个参数
                        ExprValue* paraDir = callFunStack->at(lastIndex);

                        if ((paraFilter->type == EXPR_INT || paraFilter->type == EXPR_INT64) && paraDir->type == EXPR_STRING && (paraSort->type == EXPR_INT || paraSort->type == EXPR_INT64))
                        {
                            dirPath = QString(*(QByteArray*)paraDir->value.vpoint);
                            filter |= (QDir::Filters)paraFilter->value.vint;
                            sortFlags = (QDir::SortFlags)paraSort->value.vint;
                        }
                    }
                    else
                    {
                        ExprValue* funName = callFunStack->last();
                        std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

                        QString msg = QString(u8"错误：行号 %1 语句 %2 函数 %3 参数无法匹配，请检查！").arg(curLine).arg(curStatement).arg(QStr(name));
                        AbortException(msg);
                        return 0;
                    }



                    exprRet->type = EXPR_LIST;

                    getRegularFilePath(dirPath);

                    QDir dir(dirPath);
                    if (!dir.exists())
                    {
                        //如果不是目录，是一个文件，或者压根不存在该路径，返回空列表。
                        //exprRet->value.vpoint = nullptr;

                        std::cout << dirPath.toStdString() << u8" 不是一个目录或者不存在，无法遍历目录" << std::endl;

                        std::vector<ExprValue*>* pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>();
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pData;

                        addListMapRefNum(pData);
                    }
                    else
                    {

                        QFileInfoList fiList = dir.entryInfoList(filter, sortFlags);
                        std::vector<ExprValue*>* pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>(fiList.size());
    #ifdef PIN_MEM_REF
                        newTime();
    #endif

                        for (int i = 0, c = fiList.size(); i < c; ++i)
                        {
                            ExprValue* pExpr = new ExprValue();
                            pExpr->type = EXPR_FILE;

                            FILE_VALUE_DATA* pFile = new FILE_VALUE_DATA();
                            pFile->pFileInfo = new QFileInfo(fiList.at(i));

                            pExpr->value.vpoint = pFile;

                            addListMapRefNum(pFile);

                            pData->operator[](i) = pExpr;
    #ifdef PIN_MEM_REF
                            newTime(3);
    #endif
                        }

                        exprRet->value.vpoint = pData;

                        addListMapRefNum(pData);
                    }

                }
                else
                {
                    hasError = 4;
                }
            }
            else
            {
                hasError = 4;
            }
        }
        break;

        //全局目录方法
        case currentPath_Fun:
        case homePath_Fun:
        case tempPath_Fun:
        case isAbsolutePath_Fun:
        case isRelativePath_Fun:
        case setCurrent_Fun:
        case dirRename_Fun:
        case toNativeSeparators_Fun:
        case drives_Fun:
        case pathExist_Fun:
        case rmfile_Fun:
        case wj_static_copy_Fun:
        case fileExist_Fun:
        case static_moveToTrash_Fun:
        case static_rename_Fun:
        case static_symLinkTarget_Fun:
        case static_rmdir_Fun:
        case static_rmpath_Fun:
        case static_mkpath_Fun:
        case static_mkdir_Fun:
        case static_cd_Fun:
        case static_cdUp_Fun:
        case static_open_Fun:
        case static_pathJoin_Fun:
        case static_getRegularFilePath_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj->type == EXPR_GLOBAL_PACKNAME)
            {
                if (obj->value.vpacktype == EXPR_FILE)
                {
                    switch (fun_info->fun_id)
                    {
                        //当前路径
                        case currentPath_Fun:
                        {
                            exprRet->type = EXPR_STRING;

                            std::string path = QDir::currentPath().toStdString();
                            exprRet->setString(path);
                        }
                        break;



                        case homePath_Fun:
                        {
                            exprRet->type = EXPR_STRING;

                            std::string path = QDir::homePath().toStdString();
                            exprRet->setString(path);
                        }
                        break;

                        case drives_Fun:
                        {
                            exprRet->type = EXPR_LIST;

                            QFileInfoList fiList = QDir::drives();

                            std::vector<ExprValue*>* pData = new std::vector<ExprValue*>(fiList.size());
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            exprRet->value.vpoint = pData;
                            addListMapRefNum(pData);

                            for (int i = 0, s = fiList.size(); i < s; ++i)
                            {
                                ExprValue* pExpr = new ExprValue();
#ifdef PIN_MEM_REF
                                newTime();
#endif

                                pExpr->setString(fiList.at(i).absolutePath().toStdString());
                                pData->operator[](i) = pExpr;
                            }

                        }
                        break;

                        case tempPath_Fun:
                        {
                            exprRet->type = EXPR_STRING;

                            std::string path = QDir::tempPath().toStdString();
                            exprRet->setString(path);
                        }
                        break;


                        case isAbsolutePath_Fun:
                        case isRelativePath_Fun:
                        case pathExist_Fun:
                        case toNativeSeparators_Fun:
                        case setCurrent_Fun:
                        case rmfile_Fun:
                        case fileExist_Fun:
                        case static_moveToTrash_Fun:
                        case static_symLinkTarget_Fun:
                        case static_getRegularFilePath_Fun:
                        {
                            exprRet->type = EXPR_BOOL;

                            --lastIndex; //倒数第一个参数
                            ExprValue* paraPath = callFunStack->at(lastIndex);

                            QString path(*(QByteArray*)paraPath->value.vpoint);

                            switch (fun_info->fun_id)
                            {
                                case isAbsolutePath_Fun:
                                    exprRet->value.vbool = QDir::isAbsolutePath(path);
                                break;

                                case isRelativePath_Fun:
                                    exprRet->value.vbool = QDir::isRelativePath(path);
                                break;

                                case setCurrent_Fun:
                                    exprRet->value.vbool = QDir::setCurrent(path);
                                break;

                                case toNativeSeparators_Fun:
                                {
                                    exprRet->type = EXPR_STRING;
                                    std::string pathStr = QDir::toNativeSeparators(path).toStdString();
                                    exprRet->setString(pathStr);
                                }
                                break;

                                case pathExist_Fun:
                                {
                                    QFileInfo fi(path);
                                    exprRet->value.vbool = fi.exists();//同fileExist_Fun
                                }
                                break;

                                //全局的删除文件。
                                case rmfile_Fun:
                                {
                                    exprRet->value.vbool = QFile::remove(path); //只能删除文件，删除目录会失败
                                }
                                break;

                                //获取规范化后的路径。
                                case static_getRegularFilePath_Fun:
                                {
                                    exprRet->type = EXPR_STRING;
                                    getRegularFilePath(path);

                                    exprRet->value.vpoint = new QByteArray(path.toUtf8());
#ifdef PIN_MEM_REF
                            newTime();
#endif

                                }
                                break;

                                case fileExist_Fun://对文件和文件夹都有效果。
                                {
                                    exprRet->value.vbool = QFile::exists(path);
                                }
                                break;

                                case static_moveToTrash_Fun:
                                {
                                    exprRet->value.vbool = QFile::moveToTrash(path); //删除目录会失败
                                }
                                break;

                                case static_symLinkTarget_Fun:
                                {
                                exprRet->type = EXPR_STRING;
                                std::string pathStr = QFile::symLinkTarget(path).toStdString();
                                exprRet->setString(pathStr);
                                //返回符号链接的真实文件，文件和目录都有效。
                                }
                                break;

                            }
                        }
                        break;

                    case static_rmdir_Fun:
                    case static_rmpath_Fun:
                    case static_mkpath_Fun:
                    case static_mkdir_Fun:
                    case static_cd_Fun:
                    {
                        exprRet->type = EXPR_BOOL;

                        --lastIndex; //倒数第一个参数
                        ExprValue* paraPath = callFunStack->at(lastIndex);
                        QString dirName(*(QByteArray*)paraPath->value.vpoint);

                        //如果参数是相对路径，则是在当前工作目录下，做该事情。
                        QFileInfo fi(dirName);

                        QString parentDirPath;

                        //如果是绝对路径，设置目录为绝对路径的父路径
                        if(fi.isAbsolute())
                        {
                            parentDirPath = fi.absolutePath();
                        }
                        else
                        {
                            //是相对路径，设置为当前目录的路径。则后续操作都是在当前目录下进行。
                            parentDirPath = QDir::currentPath();
                        }

                        QDir dir(parentDirPath);

                        switch(fun_info->fun_id)
                        {
                            case static_rmdir_Fun:
                            {
                                exprRet->value.vbool = dir.rmdir(dirName);
                            }
                            break;

                            case static_rmpath_Fun://删除目录。使用QDir的方法。
                            {
                                exprRet->value.vbool = dir.rmpath(dirName);
                            }
                            break;

                            case static_mkpath_Fun:
                            {
                                exprRet->value.vbool = dir.mkpath(dirName);
                            }
                            break;

                            case static_mkdir_Fun:
                            {
                                exprRet->value.vbool = dir.mkdir(dirName);
                            }
                            break;

                            case static_cd_Fun:
                            {
                                exprRet->value.vbool = dir.cd(dirName);

                                if(exprRet->value.vbool)
                                {
                                       exprRet->value.vbool = QDir::setCurrent(dir.absolutePath());
                        }
                    }
                    break;




                        }
                    }
                    break;

                    case static_open_Fun:
                    {
                        --lastIndex;
                        ExprValue* paraMode = callFunStack->at(lastIndex);

                        --lastIndex;
                        ExprValue* paraPath = callFunStack->at(lastIndex);

                        QString openMode(*(QByteArray*)paraMode->value.vpoint);

                        QString openPath(*(QByteArray*)paraPath->value.vpoint);

                        QFile* pFile = new QFile(openPath);
#ifdef PIN_MEM_REF
                            newTime();
#endif
                        //exprRet->value.vbool 要先在openFileFun中被使用。
                        bool isOk = openFileFun(pFile,openMode,exprRet,ctx);

                        exprRet->type = EXPR_FILE;

                        if (isOk)
                        {

                            FILE_VALUE_DATA* pData = new FILE_VALUE_DATA();
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            pData->pFile = pFile;
                            pData->pFileInfo = new QFileInfo(openPath);
#ifdef PIN_MEM_REF
                            newTime();
#endif

                            exprRet->value.vpoint = pData;
                            addListMapRefNum(pData);
                        }
                        else
                        {
                            exprRet->value.vpoint = nullptr;
                        }

                    }
                        break;

                    case static_cdUp_Fun:
                    {
                        QDir dir = QDir::current();

                        //std::cout << "--1" << dir.absolutePath().toStdString() << std::endl;

                        exprRet->value.vbool = dir.cdUp();

                        //std::cout << "--2" << dir.absolutePath().toStdString()<< std::endl;

                        if(exprRet->value.vbool)
                        {
                               exprRet->value.vbool = QDir::setCurrent(dir.absolutePath());
                        }
                    }
                    break;

                        case dirRename_Fun:
                        case wj_static_copy_Fun:
                        case static_rename_Fun:
                        case static_pathJoin_Fun:
                        {
                            exprRet->type = EXPR_BOOL;

                            --lastIndex; //newName
                            ExprValue* newName = callFunStack->at(lastIndex);

                            QString newpath(*(QByteArray*)newName->value.vpoint);

                            --lastIndex; //oldName
                            ExprValue* oldName = callFunStack->at(lastIndex);

                            QString oldpath(*(QByteArray*)oldName->value.vpoint);

                            switch(fun_info->fun_id)
                            {
                                case dirRename_Fun:
                                {
                                    QDir dir(oldpath);
                                    exprRet->value.vbool = dir.rename(oldpath, newpath);
                                }
                                    break;

                                case wj_static_copy_Fun:
                                {
                                       exprRet->value.vbool = QFile::copy(oldpath,newpath);
                                }
                                    break;

                                case static_rename_Fun:
                                {
                                    exprRet->value.vbool = QFile::rename(oldpath,newpath);//测试发现，对文件和目录均有效。
                                }
                                break;

                                case static_pathJoin_Fun:
                                {
                                    exprRet->type = EXPR_STRING;
                                    oldpath += QDir::separator() + newpath;

                                    exprRet->setString(oldpath.toStdString());
                            }
                                    break;
                        }


                        }
                        break;

                    }
                }
                else
                {
                    hasError = 4;
                }
            }
        }
            break;
        case exists_Fun:
        case isDir_Fun:
        case isExecutable_Fun:
        case isFile_Fun:
        case isHidden_Fun:
        case isReadable_Fun:
        case isRelative_Fun:
        case isShortcut_Fun:
        case isSymLink_Fun:
        case isSymbolicLink_Fun:
        case isWritable_Fun:
        case rmdir_Fun:
        case rmpath_Fun:
        case mkpath_Fun:
        case mkdir_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr && obj->type == EXPR_FILE)
            {
                QFileInfo* pFi = getFileInfoFromExpr(obj);
                if (pFi != nullptr)
                {
                    bool ret;

                    switch (fun_info->fun_id)
                    {
                    case  exists_Fun:
                    {
                        ret = pFi->exists();
                    }
                    break;
                    case  isDir_Fun:
                    {
                        ret = pFi->isDir();
                    }
                    break;
                    case  isExecutable_Fun:
                    {
                        ret = pFi->isExecutable();
                    }
                    break;
                    case  isFile_Fun:
                    {
                        ret = pFi->isFile();
                    }
                    break;

                    case  isHidden_Fun:
                    {
                        ret = pFi->isHidden();
                    }
                    break;

                    case  isReadable_Fun:
                    {
                        ret = pFi->isReadable();
                    }
                    break;

                    case  isRelative_Fun:
                    {
                        ret = pFi->isRelative();
                    }
                    break;

                    case  isShortcut_Fun:
                    {
                        ret = pFi->isShortcut();
                    }
                    break;

                    case  isSymLink_Fun:
                    {
                        ret = pFi->isSymLink();
                    }
                    break;
                    case  isSymbolicLink_Fun:
                    {
                        ret = pFi->isSymbolicLink();
                    }
                    break;
                    case  isWritable_Fun:
                    {
                        ret = pFi->isWritable();
                    }
                    break;

                    //删除目录。使用QDir的方法。
                    case rmdir_Fun:
                    case rmpath_Fun:
                    case mkpath_Fun:
                    case mkdir_Fun:
                    {
                        --lastIndex;
                        ExprValue* paraDirName = callFunStack->at(lastIndex);
                        QDir dir(pFi->absoluteFilePath());

                        QString dirName(*(QByteArray*)paraDirName->value.vpoint);

                        switch(fun_info->fun_id)
                        {
                            case rmdir_Fun:
                            {
                                ret = dir.rmdir(dirName);
                            }
                            break;

                            case rmpath_Fun://删除目录。使用QDir的方法。
                            {
                                ret = dir.rmpath(dirName);
                            }
                            break;

                            case mkpath_Fun:
                            {
                                ret = dir.mkpath(dirName);
                            }
                            break;

                            case mkdir_Fun:
                            {
                                ret = dir.mkdir(dirName);
                            }
                            break;
                        }
                    }
                    break;


                    }
                    //使用栈返回
                    exprRet->type = EXPR_BOOL;

                    exprRet->value.vbool = ret;

                }

            }
        }
        break;

        //不需要打开文件的操作
        case moveToTrash_Fun://删除到回收站
        case remove_Fun:
        case copy_Fun:
        case rename_Fun:

            //需要打开文件
        case wj_open_Fun:
        case size_Fun:
        case close_Fun:
        case readAll_Fun:
        case read_Fun:
        case write_Fun:
        //case writeMax_Fun:
        case seek_Fun:
        case pos_Fun:
        case read_line_Fun:
        {
            //拷贝文件
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                QFile* pFile = getQFileFromExpr(obj);
                if (pFile != nullptr)
                {
                    switch (fun_info->fun_id)
                    {
                    case moveToTrash_Fun:
                    {
                        exprRet->type = EXPR_BOOL;
                        exprRet->value.vbool = pFile->moveToTrash();;
                    }
                    break;

                    case remove_Fun:
                    {
                        exprRet->type = EXPR_BOOL;
                        exprRet->value.vbool = pFile->remove();;
                    }
                    break;

                    //拷贝文件需要一个参数
                    case copy_Fun:
                    {
                        --lastIndex;
                        if (lastIndex >= 0)
                        {
                            ExprValue* para = callFunStack->at(lastIndex);
                            //必须是字符串类型
                            if (para->type == EXPR_STRING && para->value.vpoint != nullptr)
                            {
                                QString newName(*(QByteArray*)para->value.vpoint);
                                exprRet->type = EXPR_BOOL;
                                exprRet->value.vbool = pFile->copy(newName);

                                if (!exprRet->value.vbool)
                                {
                                    QString errInfo = QString(u8"警告：拷贝文件 %1 到 %2 失败！%3").arg(pFile->fileName()).arg(newName).arg(pFile->errorString());
                                    std::cout << errInfo.toStdString() << std::endl;
                                }
                            }
                            else
                            {
                                //参数不匹配，需要字符串路径，但是不是字符串类型。
                                hasError = 3;
                                curParaIndex = 1;
                            }
                        }
                        else
                        {
                            //参数错误，缺少对应的参数。
                            hasError = 2;
                        }
                    }
                    break;

                    case rename_Fun:
                    {
                        --lastIndex;
                        if (lastIndex >= 0)
                        {
                            ExprValue* para = callFunStack->at(lastIndex);
                            //必须是字符串类型
                            if (para->type == EXPR_STRING && para->value.vpoint != nullptr)
                            {
                                QString newName(*(QByteArray*)para->value.vpoint);
                                exprRet->type = EXPR_BOOL;

                                QString oldName = pFile->fileName();

                                if (!pFile->exists())
                                {
                                    //文件不存在。
                                    exprRet->value.vbool = false;
                                    QString errInfo = QString(u8"错误：原始文件%1 不存在， 改名 %1 到 %2 失败！").arg(pFile->fileName()).arg(newName);
                                    std::cout << errInfo.toStdString() << std::endl;
                                }
                                else
                                {
                                    //如果文件打开了，则先要关闭文件。是否存在问题？
                                    if (pFile->isOpen())
                                    {
                                        QString errInfo = QString(u8"警告：文件改名之前还没有关闭，尝试关闭文件后继续改名 %1 到 %2 ").arg(pFile->fileName()).arg(newName).arg(pFile->errorString());
                                        std::cout << errInfo.toStdString() << std::endl;
                                        pFile->close();
                                    }

                                    exprRet->value.vbool = pFile->rename(oldName, newName);

                                    if (!exprRet->value.vbool)
                                    {
                                        QString errInfo = QString(u8"警告：文件改名 %1 到 %2 失败！%3").arg(pFile->fileName()).arg(newName).arg(pFile->errorString());
                                        std::cout << errInfo.toStdString() << std::endl;
                                    }
                                }
                            }
                            else
                            {
                                //参数不匹配，需要字符串路径，但是不是字符串类型。
                                hasError = 3;
                                curParaIndex = 1;
                            }
                        }
                        else
                        {
                            //参数错误，缺少对应的参数。
                            hasError = 2;
                        }
                    }
                    break;



                    case wj_open_Fun:
                    {
                        --lastIndex;
                        if (lastIndex >= 0)
                        {
                            ExprValue* para = callFunStack->at(lastIndex);
                            //必须是字符串类型
                            if (para->type == EXPR_STRING && para->value.vpoint != nullptr)
                            {
                                exprRet->type = EXPR_BOOL;

                                //如果文件打开了，则先要关闭文件。是否存在问题？
                                if (pFile->isOpen())
                                {
                                    //文件存在。
                                    exprRet->value.vbool = false;
                                    QString errInfo = QString(u8"错误：行号 %1 语句 %2 文件%3 已经在变量 %4 中打开，同一个文件不可重复打开！").arg(curLine).arg(curStatement).arg(pFile->fileName()).arg(QStr(*obj->varName));
                                    std::cout << errInfo.toStdString() << std::endl;
                                    return 0;
                                }

                                //r w rw a t
                                QString openMode(*(QByteArray*)para->value.vpoint);

                                openFileFun(pFile,openMode,exprRet,ctx);

#if 0
                                QIODevice::OpenMode mode = QIODevice::NotOpen;

                                if (openMode.contains("r"))//读
                                {
                                    mode = QIODevice::ReadOnly;
                                }

                                if (openMode.contains("w"))//写
                                {
                                    mode |= QIODevice::WriteOnly;
                                }

                                if (openMode.contains("a"))//追加
                                {
                                    mode |= QIODevice::Append;
                                }

                                if (openMode.contains("t"))//文本模式
                                {
                                    mode |= QIODevice::Text;
                                }

                                if (openMode.contains("c"))//清空模式
                                {
                                    mode |= QIODevice::Truncate;
                                }

                                int modeMatch = 0;

                                if (openMode.contains("n"))//新建文件
                                {
                                    mode |= QIODevice::NewOnly;

                                    if (pFile->exists())
                                    {
                                        //文件存在。
                                        exprRet->value.vbool = false;
                                        QString errInfo = QString(u8"错误：行号 %1 文件%2 已经存在！模式 n 下打开文件必须是一个不存在的文件！").arg(curLine).arg(pFile->fileName());
                                        //std::cout << errInfo.toStdString() << std::endl;
                                        AbortException(errInfo);
                                        //return 0;
                                    }
                                    modeMatch = 1;
                                }

                                if (openMode.contains("e"))//必须存在
                                {
                                    if (modeMatch == 1)
                                    {
                                        //不能和n 共存。
                                        exprRet->value.vbool = false;
                                        QString errInfo = QString(u8"错误：行号 %1 打开文件%2 模式错误。模式 e 和 n 无法同时存在 ！").arg(curLine).arg(pFile->fileName());
                                        //std::cout << errInfo.toStdString() << std::endl;
                                        //return 0;
                                        AbortException(errInfo);
                                    }
                                    mode |= QIODevice::ExistingOnly;

                                    if (!pFile->exists())
                                    {
                                        //文件不存在。
                                        exprRet->value.vbool = false;
                                        QString errInfo = QString(u8"错误：行号 %1 文件%2 不存在！模式 e 下打开文件必须存在该文件！").arg(curLine).arg(pFile->fileName());
                                        //std::cout << errInfo.toStdString() << std::endl;
                                        //return 0;
                                        AbortException(errInfo);
                                    }
                                }

                                exprRet->value.vbool = pFile->open(mode);

                                if (!exprRet->value.vbool)
                                {
                                    QString errInfo = QString(u8"警告：行号 %1 语句 %2 文件 %3 打开失败！%4").arg(curLine).arg(curStatement).arg(pFile->fileName()).arg(pFile->errorString());
                                    //std::cout << errInfo.toStdString() << std::endl;
                                    AbortException(errInfo);
                                }
#endif
                            }
                            else
                            {
                                //参数不匹配，需要字符串路径，但是不是字符串类型。
                                hasError = 3;
                                curParaIndex = 1;
                            }
                        }
                        else
                        {
                            //参数错误，缺少对应的参数。
                            hasError = 2;
                        }
                    }
                    break;


                    case size_Fun:
                    {
                        if (lastIndex >= 0)
                        {

                            exprRet->type = EXPR_INT64;

                            if (!pFile->exists())
                            {
                                //文件不存在。
                                exprRet->value.vint64 = 0;
                                QString errInfo = QString(u8"错误：函数%1 语句%2 文件%3 不存在！无法获取大小！").arg(getCurFunQSName()).arg(curStatement).arg(pFile->fileName());
                                std::cout << errInfo.toStdString() << std::endl;
                                return 0;
                            }

                            exprRet->value.vint64 = pFile->size();


                        }
                        else
                        {
                            //参数错误，缺少对应的参数。
                            hasError = 2;
                        }
                    }
                    break;

                    case close_Fun:
                    {
                        if (lastIndex >= 0)
                        {
                            //不要返回值，默认都返回0
                            exprRet->type = EXPR_INT;
                            pFile->close();
                        }
                        else
                        {
                            //参数错误，缺少对应的参数。
                            hasError = 2;
                        }
                    }
                        break;

                    case readAll_Fun:
                    {
                        if (!pFile->isOpen())
                        {
                            QString errInfo = QString(u8"错误：函数 %1 语句 %2 文件 %3 还未打开，读取失败！").arg(getCurFunQSName()).arg(curStatement).arg(pFile->fileName());
                            std::cout << errInfo.toStdString() << std::endl;

                            exprRet->type = EXPR_STRING;
                            exprRet->setString(""); //exprRet->value.vpoint = nullptr; //返回空字符串
                        }
                        else
                        {
                            exprRet->type = EXPR_STRING;

                            QByteArray bytes = pFile->readAll();
                            exprRet->value.vpoint = new QByteArray(std::move(bytes));
#ifdef PIN_MEM_REF
                            newTime();
#endif
                        }
                    }
                    break;


                    case read_Fun:
                    {
                        if (!pFile->isOpen())
                        {
                            QString errInfo = QString(u8"错误：函数 %1 语句 %2 文件 %3 还未打开，读取失败！").arg(getCurFunQSName()).arg(curStatement).arg(pFile->fileName());
                            std::cout << errInfo.toStdString() << std::endl;

                            exprRet->type = EXPR_STRING;
                            exprRet->setString("");  //返回空字符串

                            ExprValue* codeRet = new ExprValue;
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            codeRet->type = EXPR_INT;
                            codeRet->value.vint = -1;
                            //先返回读取的字节数
                            callFunStack->push_back(codeRet);

                        }
                        else
                        {
                            --lastIndex;
                            if (lastIndex >= 0)
                            {
                                ExprValue* para = callFunStack->at(lastIndex);
                                //必须是整数类型
                                if (para->type == EXPR_INT64 || para->type == EXPR_INT)
                                {
                                    exprRet->type = EXPR_STRING;

                                    QByteArray bytes(para->value.vint64,'\0');
                                    qint64 code = pFile->read(bytes.data(), para->value.vint64);

                                    if (code >= 0 && code < bytes.size())
                                    {
                                        bytes.truncate(code);
                                    }
                                    else
                                    {
                                        bytes.truncate(0);
                                    }

                                    exprRet->value.vpoint = new QByteArray(std::move(bytes));
#ifdef PIN_MEM_REF
                                    newTime();
#endif
                                    ExprValue* codeRet = new ExprValue;
#ifdef PIN_MEM_REF
                                    newTime();
#endif
                                    codeRet->type = EXPR_INT;
                                    codeRet->value.vint = code;
                                    //先返回读取的字节数
                                    callFunStack->push_back(codeRet);
                                }
                            }
                        }
                    }
                    break;

                    case read_line_Fun:
                    {
                        if (!pFile->isOpen())
                        {
                            QString errInfo = QString(u8"错误：函数 %1 语句 %2 文件 %3 还未打开，读取失败！").arg(getCurFunQSName()).arg(curStatement).arg(pFile->fileName());
                            std::cout << errInfo.toStdString() << std::endl;

                            ExprValue* codeRet = new ExprValue;
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            codeRet->type = EXPR_INT;
                            codeRet->value.vint = -1;
                            //先返回读取的字节数
                            callFunStack->push_back(codeRet);

                            exprRet->type = EXPR_STRING;
                            exprRet->setString(""); //返回空字符串
                        }
                        else
                        {
                            --lastIndex;
                            if (lastIndex >= 0)
                            {
                                ExprValue* para = callFunStack->at(lastIndex);
                                //必须是整数类型
                                if (para->type == EXPR_INT64 || para->type == EXPR_INT)
                                {
                                    exprRet->type = EXPR_STRING;
                                    QByteArray bytes;
                                    qint64 code = 0;

                                    if (para->value.vint == 0)
                                    {
                                        bytes = pFile->readLine();
                                        code = bytes.size();
                                    }
                                    else
                                    {
                                        bytes = QByteArray(para->value.vint64, '\0');
                                        code = pFile->readLine(bytes.data(), para->value.vint64);

                                        if (code >= 0 && code < bytes.size())
                                        {
                                            bytes.truncate(code);
                                        }
                                        else
                                        {
                                            bytes.truncate(0);
                                        }
                                    }

                                    exprRet->value.vpoint = new QByteArray(std::move(bytes));
                                    #ifdef PIN_MEM_REF
                                            newTime();
                                    #endif

                                    ExprValue* codeRet = new ExprValue;
                                    #ifdef PIN_MEM_REF
                                        newTime();
                                    #endif

                                    codeRet->type = EXPR_INT;
                                    codeRet->value.vint = code;
                                    //先返回读取的字节数
                                    callFunStack->push_back(codeRet);

                                }
                            }
                        }
                    }
                    break;


                    case write_Fun:
                    {
                        if (!pFile->isOpen())
                        {
                            QString errInfo = QString(u8"错误：函数 %1 语句 %2 文件 %3 还未打开，写入失败！").arg(getCurFunQSName()).arg(curStatement).arg(pFile->fileName());
                            std::cout << errInfo.toStdString() << std::endl;

                            exprRet->type = EXPR_INT64;
                            exprRet->value.vint64 = -1; //返回失败
                        }
                        else
                        {
                            --lastIndex;
                            ExprValue* paraSize = callFunStack->at(lastIndex);

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            //要写入的内容必须是字符串类型
                            if (para1->type == EXPR_STRING && para1->value.vpoint != nullptr)
                            {
                                exprRet->type = EXPR_INT64;

                                QByteArray* bytes = (QByteArray*)(para1->value.vpoint);

                                if (paraSize->value.vint == -1)
                                {
                                    exprRet->value.vint64 = pFile->write(*bytes);
                                }
                                else
                                {
                                    exprRet->type = EXPR_INT64;

                                    char* data = bytes->data();

                                    exprRet->value.vint64 = pFile->write(data, paraSize->value.vint);
                                }

                            }
                            else
                            {
                                exprRet->type = EXPR_INT64;
                                exprRet->value.vint64 = -1;
                            }

                        }
                    }
                    break;
#if 0
                    case writeMax_Fun:
                    {
                        if (!pFile->isOpen())
                        {
                            QString errInfo = QString(u8"错误：函数 %1 语句 %2 文件 %3 还未打开，写入失败！").arg(getCurFunQSName()).arg(curStatement).arg(pFile->fileName());
                            std::cout << errInfo.toStdString() << std::endl;

                            exprRet->type = EXPR_INT64;
                            exprRet->value.vint64 = -1; 
                        }
                        else
                        {
                            --lastIndex;
                            if (lastIndex >= 0)
                            {
                                ExprValue* paraSize = callFunStack->at(lastIndex);

                                --lastIndex;
                                ExprValue* paraText = callFunStack->at(lastIndex);

                                //要写入的内容必须是字符串类型
                                if ((paraSize->type == EXPR_INT || paraSize->type == EXPR_INT64) && (paraText->type == EXPR_STRING && paraText->value.vpoint != nullptr))
                                {
                                    exprRet->type = EXPR_INT64;

                                    QByteArray* bytes = (QByteArray*)(paraText->value.vpoint);
                                    char* data = bytes->data();

                                    exprRet->value.vint64 = pFile->write(data, paraSize->value.vint64);

                                }
                                else
                                {
                                    exprRet->type = EXPR_INT64;
                                    exprRet->value.vint64 = -1;
                                }
                            }
                        }
                    }
                    break;
#endif
                    case seek_Fun:
                    {
                        if (!pFile->isOpen())
                        {
                            QString errInfo = QString(u8"错误：函数 %1 语句 %2 文件 %3 还未打开，磁头seek 失败！").arg(getCurFunQSName()).arg(curStatement).arg(pFile->fileName());
                            std::cout << errInfo.toStdString() << std::endl;

                            exprRet->type = EXPR_BOOL;
                            exprRet->value.vbool = false; //返回失败
                        }
                        else
                        {
                            --lastIndex;
                            if (lastIndex >= 0)
                            {
                                ExprValue* para = callFunStack->at(lastIndex);
                                //必须是整数类型
                                if (para->type == EXPR_INT64 || para->type == EXPR_INT)
                                {
                                    exprRet->type = EXPR_BOOL;
                                    exprRet->value.vbool = pFile->seek(para->value.vint64); //返回失败
                                }
                            }
                        }
                    }
                        break;

                    case pos_Fun:
                    {
                        if (!pFile->isOpen())
                        {
                            QString errInfo = QString(u8"错误：函数 %1 语句 %2 文件 %3 还未打开，获取磁头位置pos 失败！").arg(getCurFunQSName()).arg(curStatement).arg(pFile->fileName());
                            std::cout << errInfo.toStdString() << std::endl;

                            exprRet->type = EXPR_INT64;
                            exprRet->value.vint64 = 0; //返回失败
                        }
                        else
                        {
                            exprRet->type = EXPR_INT64;
                            exprRet->value.vint64 = pFile->pos();
                        }
                    }
                    break;

                    }

                }
                else
                {
                    hasError = 1;
                }
            }
        }
        break;
    }


    if (hasError != 0)
    {
        int lastIndex = callFunStack->size() - 1;
        ExprValue* obj = callFunStack->at(--lastIndex);

        if (1 == hasError)
        {
            QString msg = QString(u8"错误：函数 %1 语句 %2 变量 %3 不是有效的文件类型或是 kong 类型文件！").arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(*obj->varName));
            AbortException(msg);
        }
        else if (2 == hasError)
        {
            QString msg = QString(u8"错误：函数 %1 语句 %2 变量 %3 调用成员函数 %4 参数错误，缺少必要的参数，请检查函数参数个数是否正确！").arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(*obj->varName));
            AbortException(msg);
        }
        else if (3 == hasError)
        {
            QString msg = QString(u8"错误：函数 %1 语句 %2 变量 %3 调用成员函数 %4 第 %5 个参数类型错误，参数需要是字符串类型！").arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(name)).arg(curParaIndex);
            AbortException(msg);
        }
        else if (4 == hasError)
        {
            ExprValue* funName = callFunStack->last();
            std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

            QString msg = QString(u8"错误：行号 %1 语句 %2 类名 %3 调用全局函数 %4 错误，文件类型名只能是 wj ！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(name));
            AbortException(msg);
        }

    }

    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }
    return hasError;
}

int qdate_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

    int curParaIndex = 0;

    switch (fun_info->fun_id)
    {
        //全局静态函数


        case currentDateTime_Fun:
        case now_Fun:
        //case nowDate_Fun:
        //case nowTime_Fun:

        case msleep_Fun:
        case sleep_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj->type == EXPR_GLOBAL_PACKNAME)
            {
                if(obj->value.vpacktype == EXPR_DATE)
                {
                    switch(fun_info->fun_id)
                    {
                        case currentDateTime_Fun:
                        case now_Fun:
                        {
                        exprRet->type = EXPR_DATE;
                        exprRet->value.vpoint = new QDateTime(QDateTime::currentDateTime());
    #ifdef PIN_MEM_REF
                        newTime();
    #endif
                        }
                        break;

                        case msleep_Fun:
                        {
                            isNeedRetValue = false;
                            lastIndex--;
                            ExprValue* para = callFunStack->at(lastIndex);
                            if(para->type == EXPR_INT || para->type == EXPR_INT64)
                            {
                                if(para->value.vint64 > 0)
                                {
                                    QThread::msleep(para->value.vint64);
                                }
                            }
                        }
                        break;

                        case sleep_Fun:
                        {
                            isNeedRetValue = false;
                            lastIndex--;
                            ExprValue* para = callFunStack->at(lastIndex);
                            if(para->type == EXPR_INT || para->type == EXPR_INT64)
                              {
                                  if(para->value.vint64 > 0)
                                  {
                                      QThread::sleep(para->value.vint64);
                                  }
                              }
                        }
                        break;
                    }
                }
                else
                {
                    hasError = 3;
                }
            }
            else
            {
                hasError = 3;
            }
        }

        break;

        case fromString_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj->type == EXPR_GLOBAL_PACKNAME)
            {
                if(obj->value.vpacktype == EXPR_DATE)
                {
                    --lastIndex;
                    ExprValue* formatPara = callFunStack->at(lastIndex);

                    --lastIndex;
                    ExprValue* timePara = callFunStack->at(lastIndex);

                    if(formatPara->type == EXPR_STRING && formatPara->value.vpoint != nullptr && timePara->type == EXPR_STRING && timePara->value.vpoint != nullptr)
                    {
                        exprRet->type = EXPR_DATE;
                        QString timeStr(*(QByteArray*)(timePara->value.vpoint));
                        QString formatStr(*(QByteArray*)(formatPara->value.vpoint));

                        QDateTime retValue = QDateTime::fromString(timeStr,formatStr);
                        if(retValue.isValid())
                        {
                            exprRet->value.vpoint = new QDateTime(retValue);
                            #ifdef PIN_MEM_REF
                                    newTime();
                            #endif
                        }
                    }
                    else
                    {
                        hasError = 7;
                    }
                }
                else
                {
                    hasError = 3;
                }
            }
            else
            {
                hasError = 3;
            }
        }

        break;


        case addDays_Fun:
        case addMSecs_Fun:
        case addMonths_Fun:
        case addSecs_Fun:
        case addYears_Fun:
        case setMSecsSinceEpoch_Fun:
        case setOffsetFromUtc_Fun:
        case setSecsSinceEpoch_Fun:
        case toOffsetFromUtc_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                QDateTime* pDate = getQDateTimeFromExpr(obj);
                if (pDate != nullptr)
                {
                    --lastIndex;

                    ExprValue* para = callFunStack->at(lastIndex);

                    if (para->type == EXPR_INT || para->type == EXPR_INT64)
                    {
                        exprRet->type = EXPR_DATE;

                        switch (fun_info->fun_id)
                        {
                            case addDays_Fun:
                                exprRet->value.vpoint = new QDateTime(pDate->addDays(para->value.vint64));
                                #ifdef PIN_MEM_REF
                                                            newTime();
                                #endif
                                break;
                            case addMSecs_Fun:
                                    exprRet->value.vpoint = new QDateTime(pDate->addMSecs(para->value.vint64));
                                #ifdef PIN_MEM_REF
                                                            newTime();
                                #endif
                                    break;
                            case addMonths_Fun:
                            exprRet->value.vpoint = new QDateTime(pDate->addMonths(para->value.vint));
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            break;
                        case addSecs_Fun:
                            exprRet->value.vpoint = new QDateTime(pDate->addSecs(para->value.vint64));
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            break;

                        case addYears_Fun:
                            exprRet->value.vpoint = new QDateTime(pDate->addYears(para->value.vint));
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            break;

                        case setMSecsSinceEpoch_Fun:
                            pDate->setMSecsSinceEpoch(para->value.vint64);
                            isNeedRetValue = false;
                            break;

                        case setOffsetFromUtc_Fun:
                            pDate->setMSecsSinceEpoch(para->value.vint);
                            isNeedRetValue = false;
                            break;

                        case setSecsSinceEpoch_Fun:
                            pDate->setSecsSinceEpoch(para->value.vint64);
                            isNeedRetValue = false;
                            break;

                        case toOffsetFromUtc_Fun:
                        {
                            exprRet->value.vpoint = new QDateTime(pDate->toOffsetFromUtc(para->value.vint));
                            #ifdef PIN_MEM_REF
                                                        newTime();
                            #endif
                        }
                            break;


                        }
                    }
                    else
                    {
                        curParaIndex = 1;
                        hasError = 2;
                    }
                }
                else
                {
                    hasError = 1;
                }
            }
        }
        break;


        case date_Fun:
        case isNull_Fun:
        case isValid_Fun:
        case offsetFromUtc_Fun:
        case time_Fun:
        case toLocalTime_Fun:
        case toMSecsSinceEpoch_Fun:
        case toSecsSinceEpoch_Fun:
        case toUTC_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                QDateTime* pDate = getQDateTimeFromExpr(obj);
                if (pDate != nullptr)
                {

                        switch (fun_info->fun_id)
                        {
                            case date_Fun:
                            {
                                exprRet->type = EXPR_STRING;
                                QByteArray str = pDate->date().toString("yyyy-MM-dd").toUtf8();
                                exprRet->value.vpoint = new QByteArray(std::move(str));
                                #ifdef PIN_MEM_REF
                                    newTime();
                                #endif
                            }
                                break; 
                            case time_Fun:
                                {
                                    exprRet->type = EXPR_STRING;
                                    QByteArray str = pDate->time().toString("hh:mm:ss").toUtf8();
                                    exprRet->value.vpoint = new QByteArray(std::move(str));
                                    #ifdef PIN_MEM_REF
                                           newTime();
                                    #endif
                                }
                                break;
                            case toLocalTime_Fun:
                            {
                                exprRet->type = EXPR_DATE;

                                exprRet->value.vpoint = new QDateTime(pDate->toLocalTime());
#ifdef PIN_MEM_REF
                                newTime();
#endif
                            }
                            break;

                            case toUTC_Fun:
                            {
                                exprRet->type = EXPR_DATE;

                                exprRet->value.vpoint = new QDateTime(pDate->toUTC());
#ifdef PIN_MEM_REF
                                newTime();
#endif
                            }
                            break;
                            case toMSecsSinceEpoch_Fun:
                            {
                                exprRet->type = EXPR_INT64;

                                exprRet->value.vint64 = pDate->toMSecsSinceEpoch();
                            }
                            break;


                            case toSecsSinceEpoch_Fun:
                            {
                                exprRet->type = EXPR_INT64;

                                exprRet->value.vint64 = pDate->toSecsSinceEpoch();
                            }
                            break;

                            case isNull_Fun:
                            {
                                exprRet->type = EXPR_BOOL;
                                exprRet->value.vbool = pDate->isNull();
                            }
                            break;

                            case isValid_Fun:
                            {
                                exprRet->type = EXPR_BOOL;
                                exprRet->value.vbool = pDate->isValid();
                            }
                            break;

                            case offsetFromUtc_Fun:
                            {
                                exprRet->type = EXPR_INT;
                                exprRet->value.vint = pDate->offsetFromUtc();
                            }
                            break;

                        }

                }
                else
                {

                    hasError = 1;

                }
             }
        }
            break;

        case daysTo_Fun:
        case msecsTo_Fun:
        case secsTo_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                QDateTime* pDate = getQDateTimeFromExpr(obj);
                if (pDate != nullptr)
                {
                    --lastIndex;

                    ExprValue* para = callFunStack->at(lastIndex);

                    if (para->type == EXPR_DATE)
                    {
                        exprRet->type = EXPR_INT64;

                        switch (fun_info->fun_id)
                        {
                            case daysTo_Fun:
                            {
                                QDateTime* pDst = (QDateTime*)para->value.vpoint;

                                if (pDst == nullptr)
                                {
                                    hasError = 4;
                                }
                                else
                                {
                                    exprRet->value.vint64 = pDate->daysTo(*pDst);
                                }
                            }
                                break;

                            case msecsTo_Fun:
                            {
                                QDateTime* pDst = (QDateTime*)para->value.vpoint;

                                if (pDst == nullptr)
                                {
                                    hasError = 4;
                                }
                                else
                                {
                                    exprRet->value.vint64 = pDate->msecsTo(*pDst);
                                }
                            }
                            break; 

                            case secsTo_Fun:
                            {
                                QDateTime* pDst = (QDateTime*)para->value.vpoint;

                                if (pDst == nullptr)
                                {
                                    hasError = 4;
                                }
                                else
                                {
                                    exprRet->value.vint64 = pDate->secsTo(*pDst);
                                }
                            }
                            break;
                        }

                    }
                    else
                    {
                        curParaIndex = 1;
                        hasError = 2;
                    }
                }
                else
                {
                    hasError = 1;
                }
            }
        }
        break;


        case setDate_Fun:
        case setTime_Fun:
        case toString_Fun:
        case getDateString_Fun:
        case getTimeString_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                QDateTime* pDate = getQDateTimeFromExpr(obj);
                //不可能为空了。
#if 0
                if(pDate == nullptr)
                {

                    //有几个是要设置时间的，此时要主动初始化。这里如果是链式调用会不会有问题？
                    //务必注意：20250321发现没问题，因为setDate本身没有返回值，就是修改变量自身。
                    //如果调用变量不是变量本身，则这里getVarFromSymTable不会失败。反之调用变量是一个链式的中间变量，则该变量
                    //应该存在，但是目前设计不在栈变量中的，getVarFromSymTable会失败。这里有问题，已经在下面注释完善。
                    if(fun_info->fun_id == setDate_Fun || fun_info->fun_id == setTime_Fun)
                    {
                        pDate = new QDateTime();

                        obj->value.vpoint = pDate;

                        //完善后代码，这里不能使用名称去获取原始变量。
                        //因为可能是函数返回值的链式调用。干脆从源头去避免，不允许时间的obj对应的的值是空。

#if 0
                        //必须要把原始对象也赋值修改，否则原始值不会生效。
                        SymNode* pSym = getVarFromSymTable(*(obj->varName),ctx);
                        pSym->value.vpoint = pDate;
#ifdef PIN_MEM_REF
                        newTime();
#endif
#endif
                    }
                }
#endif
                if (pDate != nullptr)
                {
                    switch(fun_info->fun_id)
                    {
                    case getDateString_Fun:
                    {
                        exprRet->type = EXPR_STRING;
                        QByteArray v = pDate->toString("yyyy-MM-dd").toUtf8();
                        exprRet->value.vpoint = new QByteArray(std::move(v));
#ifdef PIN_MEM_REF
                        newTime();
#endif
                    }
                    break;
                    case getTimeString_Fun:
                    {

                        exprRet->type = EXPR_STRING;
                        QByteArray v = pDate->toString("hh:mm:ss").toUtf8();
                        exprRet->value.vpoint = new QByteArray(std::move(v));
#ifdef PIN_MEM_REF
                        newTime();
#endif
                    }
                    break;
                        case setDate_Fun:
                        case setTime_Fun:
                        case toString_Fun:

                        {
                            --lastIndex;

                            ExprValue* para = callFunStack->at(lastIndex);

                            if (para->type == EXPR_STRING)
                            {
                                switch (fun_info->fun_id)
                                {
                                    case setDate_Fun:
                                    {
                                        //对于需要修改原值的情况。
                                        //不需要返回值
                                        isNeedRetValue = false;

                                        if (para->value.vpoint != nullptr)
                                        {
                                            QString dateStr = QString(*(QByteArray*)para->value.vpoint);
                                            dateStr = dateStr.trimmed();

                                            QRegularExpression re("^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$");
                                            QRegularExpressionMatch match = re.match(dateStr);
                                            if (match.hasMatch())
                                            {
                                                QDate v = QDate::fromString(dateStr, "yyyy-MM-dd");
                                                if (v.isValid())
                                                {
                                                    pDate->setDate(v);
                                                }
                                                else
                                                {
                                                    hasError = 8;
                                                }
                                            }
                                            else
                                            {
                                                hasError = 5;
                                            }
                                        }
                                        else
                                        {
                                            hasError = 5;
                                        }
                                    }
                                        break;

                                    case setTime_Fun:
                                    {
                                        isNeedRetValue = false;

                                        if (para->value.vpoint != nullptr)
                                        {
                                            QString timeStr = QString(*(QByteArray*)para->value.vpoint);
                                            timeStr = timeStr.trimmed();

                                            QRegularExpression re("^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$");
                                            QRegularExpressionMatch match = re.match(timeStr);
                                            if (match.hasMatch())
                                            {
                                                QTime v = QTime::fromString(timeStr, "hh:mm:ss");
                                                if (v.isValid())
                                                {
                                                    pDate->setTime(v);
                                                }
                                                else
                                                {
                                                    hasError = 8;
                                                }
                                            }
                                            else
                                            {
                                                hasError = 6;
                                            }
                                        }
                                        else
                                        {
                                            hasError = 6;
                                        }
                                    }
                                    break;


                                    case toString_Fun:
                                    {
                                        if (para->type == EXPR_STRING && para->value.vpoint != nullptr)
                                        {
                                            QString formatStr = QString(*(QByteArray*)para->value.vpoint);
                                            formatStr = formatStr.trimmed();
                                            exprRet->type = EXPR_STRING;
                                            QByteArray v = pDate->toString(formatStr).toUtf8();
                                            exprRet->value.vpoint = new QByteArray(std::move(v));
                                        #ifdef PIN_MEM_REF
                                            newTime();
                                        #endif

                                        }
                                        else
                                        {
                                            hasError = 7;
                                        }
                                    }
                                    break;
                                }

                            }
                            else
                            {
                                curParaIndex = 1;
                                hasError = 2;
                            }
                        }
                    }
                }
                else
                {
                    hasError = 1;
                }
            }
        }
            break;

    }


    if (hasError != 0)
    {

        ExprValue* funName = callFunStack->last();

        std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

        int lastIndex = callFunStack->size() - 1;
        ExprValue* obj = callFunStack->at(--lastIndex);

        switch (hasError)
        {
        case 1:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 变量 %3 不是有效的时间类型或是 kong 时间文件！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName));
                AbortException(msg);
            }
            break;
        case 2:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 变量 %3 调用成员函数 %4 第 %5 个参数类型错误，参数需要是整数类型！").arg(curLine).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(name)).arg(curParaIndex);
                AbortException(msg);
            }
            break;
        case 3:
            {
                QString msg = QString(u8"错误：行号 %1 函数 %2 语句 %3 类名 %4 调用全局函数 %5 错误，时间类型名只能是 sj ！").arg(curLine).arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(name));
                AbortException(msg);
            }
            break;
        case 4:
            {
                QString msg = QString(u8"错误：行号 %1 函数 %2 语句 %3 参数是 kong 时间类型或者是无效值，无法进行操作！").arg(curLine).arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(*obj->varName));
                AbortException(msg);
            }
            break;
        case 5:
            {
                QString msg = QString(u8"错误：行号 %1 函数 %2 语句 %3 调用 %4 函数参数必须是格式 yyyy-MM-dd 格式字符串，不能是空字符串、其它格式、或非法比如2024-22-32(月份或天数范围越界等)！").arg(curLine).arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(*obj->varName));
                AbortException(msg);
            }
            break;
        case 6:
            {
                QString msg = QString(u8"错误：行号 %1 函数 %2 语句 %3 调用 %4 函数参数必须是格式 hh:mm:ss 格式字符串，不能是空字符串、其它格式、或非法比如23-61-60(分钟或秒钟范围越界等)！").arg(curLine).arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(*obj->varName));
                AbortException(msg);
            }
            break;
        case 7:
        {
                QString msg = QString(u8"错误：行号 %1 函数 %2 语句 %3 时间格式参数必须是字符串，且满足格式规则").arg(curLine).arg(getCurFunQSName()).arg(QStr(ctx->getText()));
            AbortException(msg);
        }
        break;
        case 8:
        {
            QString msg = QString(u8"错误：行号 %1 函数 %2 语句 %3 错误的时间格式或时间值！时间字符串必须是有效的时间，比如2025-02-32 或 25:61:00 类似格式均是非法时间！(月份、天数、时钟、分钟值越界等)").arg(curLine).arg(getCurFunQSName()).arg(QStr(ctx->getText()));
            AbortException(msg);
        }
        break;
        }
    }

    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }

    return 0;
}

bool isPinListVar(int type)
{
    //哪些变量类型可以加入list
    switch (type)
    {
        case EXPR_INT:
        case EXPR_INT64:
        case EXPR_FLOAT:
        case EXPR_BOOL:
        case EXPR_CHAR:
        case EXPR_WCHAR:
        case EXPR_STRUCT://结构体变量本身
        case EXPR_STRING:
        case EXPR_U16STRING:
        case EXPR_LIST:

        case EXPR_FILE:
        case EXPR_DATE:
            return true;

    default:
        break;
    }
    return false;
}

bool isPinMapVar(int type)
{
    //哪些变量类型可以加入list
    switch (type)
    {
    case EXPR_INT:
    case EXPR_INT64:
    case EXPR_FLOAT:
    case EXPR_BOOL:
    case EXPR_CHAR:
    case EXPR_WCHAR:

    case EXPR_STRUCT://结构体变量本身
    case EXPR_STRING:
    case EXPR_U16STRING:
    case EXPR_LIST:

    case EXPR_FILE:
    case EXPR_DATE:
    case EXPR_MAP:
        return true;

    default:
        break;
    }
    return false;
}

#ifdef NDD_PIN_FUN
extern std::function<bool(QWidget*, int, void*)> s_invokeMainFun;
extern QWidget * s_pMainEdit;

int ndd_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

        //是全局方法。ndd.getMainWin();
        ExprValue* obj = callFunStack->at(lastIndex);
        if (obj->type == EXPR_GLOBAL_PACKNAME)
        {

            if (obj->value.vpacktype == EXPR_NDD)
            {

                switch (fun_info->fun_id)
                {
                    case ndd_getMainWin_Fun:
                    {
                        exprRet->type = EXPR_STRUCT;

                        STRUCT_VALUE_DATA* pData = new STRUCT_VALUE_DATA();
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        pData->pCppObj = s_pMainEdit;
                        pData->structType = "PNddMain";
                        pData->structTypeId = NddMainWin_Struct_ID;

                        exprRet->value.vpoint = pData;

                    }
                    break;

                    //新建一个编辑框
                    case ndd_newEditor_Fun:
                    {
                        isNeedRetValue = false;
                        if (s_pMainEdit != nullptr)
                        {
                            s_invokeMainFun(s_pMainEdit, 1, nullptr);
                        }

                    }
                    break;
                }
            }
            else
            {
                hasError = 1;
            }
        }
        else if (obj->type == EXPR_STRUCT)//是结构体方法 PNddMain 或 PEdit方法
        {
            switch (obj->getStructTypeId())
            {
                case NddMainWin_Struct_ID:
                {
                    switch (fun_info->fun_id)
                    {
                        //新建编辑框
                        case ndd_newEditor_Fun:
                        {
                            isNeedRetValue = false;
                            if (s_pMainEdit != nullptr)
                            {
                                s_invokeMainFun(s_pMainEdit, 1, nullptr);
                            }
                        }
                        break;

                        //获取当前编辑框中文件路径
                        case ndd_curEditFilePath_Fun:
                        {
                            QString filepath;
                            exprRet->type = EXPR_STRING;
                            if (s_pMainEdit != nullptr)
                            {
                                s_invokeMainFun(s_pMainEdit, 12, &filepath);
                            }
                            exprRet->setString(filepath.toStdString());
                        }
                        break;

                        //获取当前编辑器的句柄
                        case ndd_getCurEdit_Fun:
                        case ndd_getEdit_Fun:
                        {
                            STRUCT_VALUE_DATA* pData = new STRUCT_VALUE_DATA();
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            exprRet->type = EXPR_STRUCT;

                            if(fun_info->fun_id == ndd_getCurEdit_Fun)
                            {
                            QsciScintilla* pEdit = s_getCurEdit(s_pMainEdit);
                            pData->pCppObj = pEdit;
                            }
                            else
                            {

                                --lastIndex;
                                ExprValue* paraIndex = callFunStack->at(lastIndex);

                                PLUGIN_COMMON_PARA para;
                                para.inputCode = paraIndex->value.vint;

                                if(s_invokeMainFun(s_pMainEdit, 18, &para))
                                {
                                    pData->pCppObj = (QsciScintilla* )para.outputData;
                                }
                                else
                                {
                                    pData->pCppObj = (QsciScintilla* )(0);
                                    QString warn = QString(u8"警告: 行号 %1 语句 %2 获取id为 %3 的编辑器失败，可能不存在对应编辑器框！").arg(curLine).arg(curStatement).arg(para.inputCode);
                                    std::cout << warn.toStdString() << std::endl;
                                }
                            }

                            pData->structType = "PEdit";
                            pData->structTypeId = Editor_Struct_ID;

                            exprRet->value.vpoint = pData;
                        }
                        break;


                    }
                }
                    break;

                case Editor_Struct_ID:
                {

                    STRUCT_VALUE_DATA* pData = (STRUCT_VALUE_DATA*)obj->value.vpoint;
                    QsciScintilla* pEdit = std::any_cast<QsciScintilla*>(pData->pCppObj);
                    if (pEdit != nullptr)
                    {
                        switch (fun_info->fun_id)
                        {
                            //获取当前编辑框内容
                        case ndd_getText_Fun:
                        {
                            exprRet->type = EXPR_STRING;
                            QByteArray bytes = pEdit->text().toUtf8();
                            exprRet->value.vpoint = new QByteArray(std::move(bytes));
#ifdef PIN_MEM_REF
                            newTime();
#endif
                        }
                        break;

                        //获取某行。行号是从0开始的。
                        case ndd_getLine_Fun:
                        {
                            --lastIndex;
                            ExprValue* paraLineNum = callFunStack->at(lastIndex);
                            exprRet->type = EXPR_STRING;

                            //如果行是有内容的，而不是对齐行那种，则实际取其值
                            int curLineLength = pEdit->SendScintilla(SCI_LINELENGTH, paraLineNum->value.vint);

                            if (curLineLength > 0)
                            {
                                char* contens = new char[curLineLength + 1];
                                memset(contens, 0, curLineLength + 1);

                                pEdit->SendScintilla(SCI_GETLINE, paraLineNum->value.vint, contens);
                                exprRet->value.vpoint = new QByteArray(contens, curLineLength);
#ifdef PIN_MEM_REF
                                newTime();
#endif
                                delete[]contens;
                            }
                            else
                            {
                                exprRet->setString("");
                            }
                        }
                        break;

                        //获取行数量
                        case ndd_lineCount_Fun:
                        {
                            exprRet->type = EXPR_INT;
                            exprRet->value.vint = pEdit->lines();

                        }
                        break;

                        //设置当前编辑框内容
                        case ndd_setText_Fun:
                        {
                            isNeedRetValue = false;

                            --lastIndex;
                            ExprValue* paraStr = callFunStack->at(lastIndex);
                            QString text(*(QByteArray*)paraStr->value.vpoint);

                            pEdit->setText(text);
                        }
                        break;

                        //选择文本。选择从pos1到pos2的内容。注意是按照字节。
                        //如果有汉字，pos在汉字的中间，则会对齐到汉字的边界上。
                        //即选择时按照字符来换算的，但是pos本身是字节。
                        case ndd_setsel_Fun:
                        case ndd_insertAtPos_Fun:
                        case ndd_deleteRange_Fun:
                        case ndd_getTextRange_Fun:
                        {
                            isNeedRetValue = false;

                            --lastIndex;
                            ExprValue* para2 = callFunStack->at(lastIndex);

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            switch (fun_info->fun_id)
                            {
                            case ndd_setsel_Fun:
                            {
                                pEdit->SendScintilla(SCI_SETSEL, para1->value.vint, para2->value.vint);
                            }
                            break;
                            case ndd_insertAtPos_Fun:
                            {
                                pEdit->SendScintilla(SCI_INSERT_UTF8_BYTES, para1->value.vint, para2->value.vpoint);
                            }
                            break;
                            case ndd_deleteRange_Fun:
                            {
                                //SCI_DELETERANGE(int start, int lengthDelete)
                                pEdit->SendScintilla(SCI_DELETERANGE, para1->value.vint, para2->value.vint);
                            }
                            break;
                            case ndd_getTextRange_Fun:
                            {
                                isNeedRetValue = true;
                                exprRet->type = EXPR_STRING;

                                //SCI_GETTEXTRANGE(0, int Sci_TextRange)
                                //tr.lpstrText 长度必须是len+1,预览一个
                                if (para2->value.vint > 0)
                                {
                                    QByteArray bytes(para2->value.vint+1,'\0');
                                    Sci_TextRange tr;
                                    tr.chrg.cpMin = static_cast<Sci_PositionCR>(para1->value.vint);
                                    tr.chrg.cpMax = static_cast<Sci_PositionCR>(para1->value.vint + para2->value.vint);
                                    tr.lpstrText = bytes.data();

                                    pEdit->SendScintilla(SCI_GETTEXTRANGE, 0, &tr);
                                    exprRet->setStringBytes(bytes);
                            }
                                else
                                {
                                    exprRet->setString("");
                        }
                            }
                        break;
                            }
                        }
                        break;

                        case ndd_gotoPos_Fun:
                        case ndd_gotoLine_Fun:
                        case ndd_setcurpos_Fun:
                        case ndd_setanchor_Fun:
                        case ndd_setselstart_Fun:
                        case ndd_setselend_Fun:
                        case ndd_setemptysel_Fun:
                        case ndd_replaceSelText_Fun:
                        {
                            isNeedRetValue = false;

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            switch (fun_info->fun_id)
                            {
                            case ndd_gotoPos_Fun:
                            {
                                pEdit->SendScintilla(SCI_GOTOPOS, para1->value.vint);
                            }
                            break;

                            case ndd_gotoLine_Fun:
                            {
                                pEdit->SendScintilla(SCI_GOTOLINE, para1->value.vint);
                            }
                            break;

                            case ndd_setcurpos_Fun:
                            {
                                pEdit->SendScintilla(SCI_SETCURRENTPOS, para1->value.vint);
                            }
                            break;

                            case ndd_setanchor_Fun:
                            {
                                pEdit->SendScintilla(SCI_SETANCHOR, para1->value.vint);
                            }
                            break;

                            case ndd_setselstart_Fun:
                            {
                                pEdit->SendScintilla(SCI_SETSELECTIONSTART, para1->value.vint);
                            }
                            break;

                            case ndd_setselend_Fun:
                            {
                                pEdit->SendScintilla(SCI_SETSELECTIONEND, para1->value.vint);
                            }
                            break;

                            case ndd_setemptysel_Fun:
                            {
                                pEdit->SendScintilla(SCI_SETEMPTYSELECTION, para1->value.vint);
                            }
                            break;

                            case ndd_replaceSelText_Fun:
                            {
                                QString text = QString::fromStdString(para1->getString());

                                pEdit->replaceSelectedText(text);
                            }
                            break;

                            }
                        }
                        break;

                        case ndd_getcurpos_Fun:
                        case ndd_getanchor_Fun:
                        case ndd_getselstart_Fun:
                        {
                            exprRet->type = EXPR_INT;

                            switch (fun_info->fun_id)
                            {
                            case ndd_getcurpos_Fun:
                            {
                                exprRet->value.vint = pEdit->SendScintilla(SCI_GETCURRENTPOS);
                            }
                            break;

                            case ndd_getanchor_Fun:
                            {
                                exprRet->value.vint = pEdit->SendScintilla(SCI_GETANCHOR);
                            }
                            break;

                            case ndd_getselstart_Fun:
                            {
                                exprRet->value.vint = pEdit->SendScintilla(SCI_GETSELECTIONSTART);
                            }
                            break;

                            case ndd_getselend_Fun:
                            {
                                exprRet->value.vint = pEdit->SendScintilla(SCI_GETSELECTIONEND);
                            }
                            break;
                            }
                        }
                        break;

                        case ndd_selectall_Fun:
                        {
                            isNeedRetValue = false;
                            pEdit->SendScintilla(SCI_SELECTALL);
                        }
                            break;

                        case ndd_removeSelText_Fun:
                        {
                            isNeedRetValue = false;
                            pEdit->removeSelectedText();
                        }
                        break;

                        case ndd_beginundo_Fun:
                        case ndd_endundo_Fun:
                        {
                            isNeedRetValue = false;
                            pEdit->SendScintilla((fun_info->fun_id == ndd_beginundo_Fun)?SCI_BEGINUNDOACTION: SCI_ENDUNDOACTION);
                        }
                        break;

                        case ndd_getSelText_Fun:
                        {
                            exprRet->setString(pEdit->selectedText().toStdString());
                        }
                        break;

                        case ndd_lineFromPos_Fun:
                        case ndd_posFromLine_Fun:
                        case ndd_getLineEndPos_Fun:
                        case ndd_lineLength_Fun:
                        case ndd_posBefore_Fun:
                        case ndd_posAfter_Fun:
                        {
                            exprRet->type = EXPR_INT;
                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            switch (fun_info->fun_id)
                            {
                            case ndd_lineFromPos_Fun:
                            {
                                exprRet->value.vint = pEdit->SendScintilla(SCI_LINEFROMPOSITION, para1->value.vint);
                            }
                            break;

                            case ndd_posFromLine_Fun:
                            {
                                exprRet->value.vint = pEdit->SendScintilla(SCI_POSITIONFROMLINE, para1->value.vint);
                            }
                            break;

                            case ndd_getLineEndPos_Fun:
                            {
                                exprRet->value.vint = pEdit->SendScintilla(SCI_GETLINEENDPOSITION, para1->value.vint);
                            }
                            break;

                            case ndd_lineLength_Fun:
                            {
                                exprRet->value.vint = pEdit->SendScintilla(SCI_LINELENGTH, para1->value.vint);
                            }
                            break;

                            case ndd_posBefore_Fun:
                            {
                                exprRet->value.vint = pEdit->SendScintilla(SCI_POSITIONBEFORE, para1->value.vint);
                            }
                            break;

                            case ndd_posAfter_Fun:
                            {
                                exprRet->value.vint = pEdit->SendScintilla(SCI_POSITIONAFTER, para1->value.vint);
                        }
                            break;


                            }
                        }
                            break;

                        case ndd_highLight_Fun:
                        case ndd_clear_highLight_Fun:
                        {
                            --lastIndex;
                            ExprValue* paraColor = callFunStack->at(lastIndex);
                            if (paraColor->value.vint > 5 && paraColor->value.vint < 0)
                            {
                                paraColor->value.vint = 0;
                            }

                            --lastIndex;
                            ExprValue* paraLen = callFunStack->at(lastIndex);

                            --lastIndex;
                            ExprValue* paraStart = callFunStack->at(lastIndex);

                            if (ndd_highLight_Fun == fun_info->fun_id)
                            {
                                pEdit->SendScintilla(SCI_SETINDICATORCURRENT, paraColor->value.vint + SCE_UNIVERSAL_FOUND_STYLE_EXT5);
                                pEdit->SendScintilla(SCI_INDICATORFILLRANGE, paraStart->value.vint, paraLen->value.vint);
                            }
                            else
                            {
                                pEdit->SendScintilla(SCI_SETINDICATORCURRENT, paraColor->value.vint + SCE_UNIVERSAL_FOUND_STYLE_EXT5);
                                pEdit->SendScintilla(SCI_INDICATORCLEARRANGE, paraStart->value.vint, paraLen->value.vint);

                            }
                        }
                        break;

                        case ndd_clearAllHighLight_Fun:
                        {
                            int docEnd = pEdit->length();
                            for (int i = 0; i < 5; ++i)
                            {
                                pEdit->SendScintilla(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_FOUND_STYLE_EXT5 + i);
                                pEdit->SendScintilla(SCI_INDICATORCLEARRANGE, 0, docEnd);
                            }
                        }
                        break;
                        }
                    }
                    else
                    {
                        hasError = 3;
                    }
                }
                    break;
            }
        }
        else
        {
            hasError = 2;
        }


    if (hasError != 0)
    {
        int lastIndex = callFunStack->size() - 1;
        ExprValue* obj = callFunStack->at(--lastIndex);

        ExprValue* funName = callFunStack->last();
        std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

        if (1 == hasError)
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2 类名 %3 调用全局函数 %4 错误，编辑器类型名只能是 ndd ！").arg(curLine).arg(curStatement).arg(QStr(*obj->varName)).arg(QStr(name));
            AbortException(msg);
        }
        else if (2 == hasError)
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2  变量 %3 调用函数 %4 错误，类型或变量没有对应的方法 %4").arg(curLine).arg(curStatement).arg(QStr(*obj->varName)).arg(QStr(name));
            AbortException(msg);
        }
        else if (3 == hasError)
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2  变量 %3 调用函数 %4 错误，变量没有绑定编辑器实体！").arg(curLine).arg(curStatement).arg(QStr(*obj->varName)).arg(QStr(name));
            AbortException(msg);
        }

    }


    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }
    return 0;

}
#endif

int zf_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    //int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

    //ExprValue* errorPara = nullptr;

    switch (fun_info->fun_id)
    {
        case zf_num_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            exprRet->type = EXPR_INT;
            exprRet->value.vint = static_cast<int>(obj->value.vuschar);

        }
        break;

        case zf_hex_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            exprRet->type = EXPR_STRING;
            //QByteArray* pBytes = new QByteArray();
            QByteArray v = QByteArray::number(int(obj->value.vuschar), 16);
            exprRet->value.vpoint = new QByteArray(std::move(v));
#ifdef PIN_MEM_REF
    newTime();
#endif
        }
        break;
    }

    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }
    return 0;
}

int qchar_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

    ExprValue* errorPara = nullptr;

    switch (fun_info->fun_id)
    {
    case qchar_unicode_Fun:
    {
        ExprValue* obj = callFunStack->at(lastIndex);

        switch (fun_info->fun_id)
        {
        case qchar_unicode_Fun:
        {
            exprRet->type = EXPR_INT;
            exprRet->value.vint = obj->value.vwchar;
        }
        break;

        default:
            break;
        }
    }
        break;

    //返回字符串，把宽字符的数字，返回字符串形式。
    case qchar_number_Fun:
    {
         ExprValue* obj = callFunStack->at(lastIndex);

        --lastIndex;
        ExprValue* paraBase = callFunStack->at(lastIndex);
        int base = paraBase->value.vint;
        exprRet->type = EXPR_STRING;

        QByteArray ret = QByteArray::number(obj->value.vwchar,base);

        exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
    newTime();
#endif
    }
        break;

    case  qchar_isDigit_Fun:
    case  qchar_isLetter_Fun:
    case  qchar_isLetterOrNumber_Fun:
    case  qchar_isPrint_Fun:
    case  qchar_isLower_Fun:
    case  qchar_isUpper_Fun:
    {
        ExprValue* obj = callFunStack->at(lastIndex);
        exprRet->type = EXPR_BOOL;

        switch (fun_info->fun_id)
        {
        case qchar_isDigit_Fun:
        {
            exprRet->value.vbool = obj->getQChar().isDigit();
        }
        break;
        case qchar_isLetter_Fun:
        {
            exprRet->value.vbool = obj->getQChar().isLetter();
        }
        break;
        case qchar_isLetterOrNumber_Fun:
        {
            exprRet->value.vbool = obj->getQChar().isLetterOrNumber();
        }
        break;
        case qchar_isPrint_Fun:
        {
            exprRet->value.vbool = obj->getQChar().isPrint();
        }
        break;
        case qchar_isLower_Fun:
        {
            exprRet->value.vbool = obj->getQChar().isLower();
        }
        break;
        case qchar_isUpper_Fun:
        {
            exprRet->value.vbool = obj->getQChar().isUpper();
        }
        break;

        default:
            break;
        }
    }
            break;
    }

    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }
    return 0;
}

//需要类型，needType，实际类型pExpr
int paraError(PinParser::RealCallFunContext* ctx, ExprValue* pExpr, int needType, int errParaInex=-1)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    ExprValue* funName = callFunStack->last();

    std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

    QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 第 %4 个参数类型是 %5，类型无法匹配，该参数需要是 %6").arg(curLine).arg(curStatement).arg(QStr(name))
            .arg(errParaInex).arg(getExpeTypeValue(pExpr->type,pExpr)).arg(getExpeTypeValue(needType));

    AbortException(msg);
    return 0;
}

int u16string_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif


    ExprValue* obj = callFunStack->at(lastIndex);
    QString* pBytes = (QString*)obj->value.vpoint;

    switch (fun_info->fun_id)
    {

    case qstr_number_Fun:
    {
        ExprValue* obj = callFunStack->at(lastIndex);
        if (obj->type == EXPR_GLOBAL_PACKNAME)
        {
            if (obj->value.vpacktype == EXPR_U16STRING)
            {
                //先取出参数个数。
                int callParaNum = lastIndex;

                //1个参数
                if (1 == callParaNum)
                {
                    --lastIndex;
                    ExprValue* para1 = callFunStack->at(lastIndex);

                    if (para1->type == EXPR_INT || para1->type == EXPR_INT64)
                    {
                        exprRet->type = EXPR_U16STRING;
                        QString* pRet = new QString();
                        pRet->setNum(para1->value.vint64);
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pRet;

                    }
                    else if (para1->type == EXPR_FLOAT)
                    {
                        exprRet->type = EXPR_U16STRING;
                        QString* pRet = new QString();
                        pRet->setNum(para1->value.vfloat);
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pRet;

                    }
                }
                else if (2 == callParaNum)
                {
                    --lastIndex;
                    ExprValue* para2 = callFunStack->at(lastIndex);

                    --lastIndex;
                    ExprValue* para1 = callFunStack->at(lastIndex);

                    if ((para1->type == EXPR_INT || para1->type == EXPR_INT64) && para2->type == EXPR_INT)
                    {
                        exprRet->type = EXPR_U16STRING;
                        QString* pRet = new QString();
                        pRet->setNum(para1->value.vint64, para2->value.vint);
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pRet;

                    }
                    else if ((para1->type == EXPR_FLOAT) && para2->type == EXPR_CHAR)
                    {
                        exprRet->type = EXPR_U16STRING;
                        QString* pRet = new QString();
                        pRet->setNum(para1->value.vfloat, para2->value.vchar);
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pRet;

                    }
                }
                else if (3 == callParaNum)
                {
                    --lastIndex;
                    ExprValue* para3 = callFunStack->at(lastIndex);

                    --lastIndex;
                    ExprValue* para2 = callFunStack->at(lastIndex);

                    --lastIndex;
                    ExprValue* para1 = callFunStack->at(lastIndex);

                    if ((para1->type == EXPR_FLOAT) && para2->type == EXPR_CHAR && para3->type == EXPR_INT)
                    {
                        exprRet->type = EXPR_U16STRING;
                        QString* pRet = new QString();
                        pRet->setNum(para1->value.vfloat, para2->value.vchar, para3->value.vint);
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pRet;

                    }
                }
                else
                {
                    QString msg = QString(u8"错误：行号 %1 语句 %2 参数格式错误。setNum 函数有5种形式，均无法匹配！").arg(curLine).arg(curStatement);
                    AbortException(msg);
                }
            }
            else
            {
                hasError = 2;
            }
        }
    }
    break;


    case qstr_append_Fun:
    case qstr_contains_Fun:
    case qstr_count_Fun:
    case qstr_endsWith_Fun:
    case qstr_startsWith_Fun:
    case qstr_push_back_Fun:
    case qstr_push_front_Fun:
    {

        ExprValue* paraCs = nullptr;
        Qt::CaseSensitivity cs = Qt::CaseSensitive;

        //下面4个有大小写区分。
        switch (fun_info->fun_id)
        {
            case qstr_contains_Fun:
            case qstr_count_Fun:
            case qstr_endsWith_Fun:
            case qstr_startsWith_Fun:
            {
                --lastIndex;
                paraCs = callFunStack->at(lastIndex);
                cs = (Qt::CaseSensitivity)paraCs->value.vint;
            }
            break;
        }

        --lastIndex;
        ExprValue* para = callFunStack->at(lastIndex);

        if ((para->type == EXPR_U16STRING || para->type == EXPR_STRING ) && para->value.vpoint != nullptr)
        {
            QString* pStr = nullptr;
            //兼容zfc
            if (para->type == EXPR_STRING)
            {
                pStr = new QString(*(QByteArray*)para->value.vpoint);
#ifdef PIN_MEM_REF
                        newTime();
#endif
            }
            else
            {
                pStr = (QString*)para->value.vpoint;
            }

            switch (fun_info->fun_id)
            {
            case qstr_append_Fun:
            {
                isNeedRetValue = false;

                pBytes->append(*pStr);
            }
            break;
            case qstr_contains_Fun:
            {
                exprRet->type = EXPR_BOOL;
                exprRet->value.vbool = pBytes->contains(*pStr,cs);
            }
            break;
            case qstr_count_Fun:
            {
                exprRet->type = EXPR_INT;
                exprRet->value.vint = pBytes->count(*pStr,cs);
            }
            break;
            case qstr_endsWith_Fun:
            {
                exprRet->type = EXPR_BOOL;
                exprRet->value.vbool = pBytes->endsWith(*pStr,cs);
            }
            break;

            case qstr_startsWith_Fun:
            {
                exprRet->type = EXPR_BOOL;
                exprRet->value.vbool = pBytes->startsWith(*pStr,cs);
            }

            break;

            case qstr_push_back_Fun:
            {
                isNeedRetValue = false;
                pBytes->push_back(*pStr);
            }
            break;

            case qstr_push_front_Fun:
            {
                isNeedRetValue = false;
                pBytes->push_front(*pStr);
            }
            break;
            }

            if (para->type == EXPR_STRING)
            {
                delete pStr;
#ifdef PIN_MEM_REF
                        freeTimes++;
#endif
            }
        }
        else if (para->type == EXPR_CHAR)
        {
            switch (fun_info->fun_id)
            {
            case qstr_append_Fun:
            {
                isNeedRetValue = false;

                pBytes->append(QChar(para->value.vchar));
            }
            break;
            case qstr_contains_Fun:
            {
                exprRet->type = EXPR_BOOL;
                exprRet->value.vbool = pBytes->contains(QChar(para->value.vchar),cs);
            }
            break;
            case qstr_count_Fun:
            {
                exprRet->type = EXPR_INT;
                exprRet->value.vint = pBytes->count(QChar(para->value.vchar),cs);
            }
            break;
            case qstr_endsWith_Fun:
            {
                exprRet->type = EXPR_BOOL;
                exprRet->value.vbool = pBytes->endsWith(QChar(para->value.vchar),cs);
            }
            break;

            case qstr_startsWith_Fun:
            {
                exprRet->type = EXPR_BOOL;
                exprRet->value.vbool = pBytes->startsWith(QChar(para->value.vchar),cs);
            }
            break;

            case qstr_push_back_Fun:
            {
                isNeedRetValue = false;
                pBytes->push_back(QChar(para->value.vchar));
            }
            break;

            case qstr_push_front_Fun:
            {
                isNeedRetValue = false;
                pBytes->push_front(QChar(para->value.vchar));
            }
            break;


            }
        }
        else if (para->type == EXPR_WCHAR)
        {
        switch (fun_info->fun_id)
        {
        case qstr_append_Fun:
        {
            isNeedRetValue = false;

            pBytes->append(QChar(para->value.vwchar));
        }
        break;
        case qstr_contains_Fun:
        {
            exprRet->type = EXPR_BOOL;
            exprRet->value.vbool = pBytes->contains(QChar(para->value.vwchar),cs);
        }
        break;
        case qstr_count_Fun:
        {
            exprRet->type = EXPR_INT;
            exprRet->value.vint = pBytes->count(QChar(para->value.vwchar),cs);
        }
        break;
        case qstr_endsWith_Fun:
        {
            exprRet->type = EXPR_BOOL;
            exprRet->value.vbool = pBytes->endsWith(QChar(para->value.vwchar),cs);
        }
        break;

        case qstr_startsWith_Fun:
        {
            exprRet->type = EXPR_BOOL;
            exprRet->value.vbool = pBytes->startsWith(QChar(para->value.vwchar),cs);
        }
        break;

        case qstr_push_back_Fun:
        {
            isNeedRetValue = false;
            pBytes->push_back(QChar(para->value.vwchar));
        }
        break;

        case qstr_push_front_Fun:
        {
            isNeedRetValue = false;
            pBytes->push_front(QChar(para->value.vwchar));
        }
        break;


        }
        }
    }
    break;

    case qstr_chop_Fun:
    case qstr_chopped_Fun:
    case qstr_left_Fun:
    case qstr_right_Fun:
    {

        //访问字符串中某一个字符
        --lastIndex; //第一个参数
        ExprValue* para = callFunStack->at(lastIndex);
        if (para->type == EXPR_INT || para->type == EXPR_INT64)
        {
            switch (fun_info->fun_id)
            {

            case qstr_chop_Fun:
            {
                isNeedRetValue = false;
                pBytes->chop(para->value.vint64);
            }
            break;

            case qstr_chopped_Fun:
            {
                exprRet->type = EXPR_U16STRING;

                if (para->value.vint64 > (pBytes->size()) || para->value.vint64 < 0)
                {
                    QString msg = QString(u8"错误：行 %1 语句 %2 chopped 尾巴字符失败，长度值 %3 超过当前字符串长度 %4 (下标从0开始计算)！").arg(curLine).arg(curStatement).arg(para->value.vint64).arg(pBytes->size());
                    AbortException(msg);
                }
                QString ret = pBytes->chopped(para->value.vint64);
                exprRet->value.vpoint = new QString(std::move(ret));
#ifdef PIN_MEM_REF
                newTime();
#endif
            }
            break;

            case qstr_left_Fun:
            {
                exprRet->type = EXPR_U16STRING;
                QString ret = pBytes->left(para->value.vint);
                exprRet->value.vpoint = new QString(std::move(ret));
#ifdef PIN_MEM_REF
                newTime();
#endif
            }
            break;
            case qstr_right_Fun:
            {
                exprRet->type = EXPR_U16STRING;
                QString ret = pBytes->right(para->value.vint);
                exprRet->value.vpoint = new QString(std::move(ret));
#ifdef PIN_MEM_REF
                newTime();
#endif
            }
            break;

            }
        }
        else
        {
            hasError = 1;
        }
    }
    break;

    case qstr_leftJustified_Fun:
    case qstr_rightJustified_Fun:
    {
        //访问字符串中某一个字符
        --lastIndex; //倒数第一个参数

        ExprValue* paraTrun = callFunStack->at(lastIndex);

        --lastIndex; //倒数第2个参数

        ExprValue* paraFill = callFunStack->at(lastIndex);

        --lastIndex; //倒数第3个参数
        ExprValue* paraWidth = callFunStack->at(lastIndex);

        exprRet->type = EXPR_U16STRING;

        QString ret;
        if (fun_info->fun_id == qstr_leftJustified_Fun)
        {
            ret = pBytes->leftJustified(paraWidth->value.vint, QChar(paraFill->value.vwchar), (paraTrun->value.vint != 0));
        }
        else
        {
            ret = pBytes->rightJustified(paraWidth->value.vint, QChar(paraFill->value.vwchar), (paraTrun->value.vint != 0));
        }
        exprRet->value.vpoint = new QString(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;

    //重载变参类型，要检查参数具体形式。
    case qstr_replace_Fun:
    {
        //先取出参数个数。
        int callParaNum = lastIndex;
        isNeedRetValue = false;

        bool isMatch = true;
        //2个参数
        if (2 == callParaNum)
        {
            --lastIndex;
            ExprValue* para2 = callFunStack->at(lastIndex);

            --lastIndex;
            ExprValue* para1 = callFunStack->at(lastIndex);

            int type = para1->type << 16 | para2->type;

            switch (type)
            {
                case EXPR_U16STRING << 16 | EXPR_U16STRING:
                {
                    pBytes->replace(*(QString*)para1->value.vpoint, *(QString*)para2->value.vpoint);
                }
                    break;

                case EXPR_STRING << 16 | EXPR_STRING:
                {
                    QString before(*(QByteArray*)para1->value.vpoint);
                    QString after(*(QByteArray*)para2->value.vpoint);

                    pBytes->replace(before, after);
                }
                    break;

                case EXPR_STRING << 16 | EXPR_U16STRING:
                {
                    QString before(*(QByteArray*)para1->value.vpoint);

                    pBytes->replace(before, *(QString*)para2->value.vpoint);
                }
                    break;

                case EXPR_U16STRING << 16 | EXPR_STRING:
                {
                    QString after(*(QByteArray*)para2->value.vpoint);

                    pBytes->replace(*(QString*)para1->value.vpoint,after);
                }
                    break;

                case EXPR_WCHAR << 16 | EXPR_WCHAR:
                {
                    pBytes->replace(QChar(para1->value.vwchar), QChar(para2->value.vwchar));
                }
                    break;

                case EXPR_CHAR << 16 | EXPR_WCHAR:
                {
                    pBytes->replace(QChar(para1->value.vchar), QChar(para2->value.vwchar));
                }
                    break;

                case EXPR_CHAR << 16 | EXPR_CHAR:
                {
                    pBytes->replace(QChar(para1->value.vchar), QChar(para2->value.vchar));
                }
                    break;

                case EXPR_WCHAR << 16 | EXPR_CHAR:
                {
                    pBytes->replace(QChar(para1->value.vwchar), QChar(para2->value.vchar));
                }
                    break;

                case EXPR_WCHAR << 16 | EXPR_U16STRING:
                {
                    pBytes->replace(QChar(para1->value.vwchar), *(QString*)para2->value.vpoint);
                }
                    break;

                case EXPR_CHAR << 16 | EXPR_U16STRING:
                {
                    pBytes->replace(QChar(para1->value.vchar), *(QString*)para2->value.vpoint);
                }
                    break;

                case EXPR_WCHAR << 16 | EXPR_STRING:
                {
                    QString after(*(QByteArray*)para2->value.vpoint);
                    pBytes->replace(QChar(para1->value.vwchar), after);
                }
                    break;

                case EXPR_CHAR << 16 | EXPR_STRING:
                {
                    QString after(*(QByteArray*)para2->value.vpoint);
                    pBytes->replace(QChar(para1->value.vchar), after);
                }
                    break;

                default:
                {
                    isMatch = false;
                }
                    break;
            }


        }
        else if (3 == callParaNum)
        {
            --lastIndex;
            ExprValue* para3 = callFunStack->at(lastIndex);

            --lastIndex;
            ExprValue* para2 = callFunStack->at(lastIndex);

            --lastIndex;
            ExprValue* para1 = callFunStack->at(lastIndex);

            //匹配QByteArray& replace(int pos, int len, const QByteArray& after)

            if ((para1->type == EXPR_INT || para1->type == EXPR_INT64) && (para2->type == EXPR_INT || para2->type == EXPR_INT64))
            {
                if(para3->type == EXPR_U16STRING)
                {
                    pBytes->replace(para1->value.vint, para2->value.vint, *(QString*)para3->value.vpoint);
                }
                else if(para3->type == EXPR_STRING)
                {
                    QString after(*(QByteArray*)para3->value.vpoint);
                    pBytes->replace(para1->value.vint, para2->value.vint, after);
                }
                else
                {
                    isMatch = false;
                }
            }
        }
        else if (4 == callParaNum)
        {
            //匹配QByteArray &QByteArray::replace(int pos, int len, const char *after, int alen);

            --lastIndex;
            ExprValue* para4 = callFunStack->at(lastIndex);

            --lastIndex;
            ExprValue* para3 = callFunStack->at(lastIndex);

            --lastIndex;
            ExprValue* para2 = callFunStack->at(lastIndex);

            --lastIndex;
            ExprValue* para1 = callFunStack->at(lastIndex);

            if ((para1->type == EXPR_INT || para1->type == EXPR_INT64) && (para2->type == EXPR_INT || para2->type == EXPR_INT64) && para3->type == EXPR_U16STRING && (para4->type == EXPR_INT || para4->type == EXPR_INT64))
            {
                const QChar* after = ((QString*)para3->value.vpoint)->constData();

                pBytes->replace(para1->value.vint, para2->value.vint, after, para4->value.vint);
            }
            else
            {
                isMatch = false;
            }
        }

        if(!isMatch)
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2 参数格式错误。replace 函数有5种形式，均无法匹配！").arg(curLine).arg(curStatement);
            AbortException(msg);
        }
    }
    break;



    case qstr_remove_Fun:
    {
        isNeedRetValue = false;

        //访问字符串中某一个字符
        --lastIndex; //倒数第一个参数

        ExprValue* paraLen = callFunStack->at(lastIndex);

        --lastIndex; //倒数第2个参数

        ExprValue* paraPos = callFunStack->at(lastIndex);

        pBytes->remove(paraPos->value.vint, paraLen->value.vint);

    }
    break;

    case qstr_mid_Fun:
    {
        //访问字符串中某一个字符
        --lastIndex; //倒数第一个参数
        ExprValue* paraLen = callFunStack->at(lastIndex);

        --lastIndex; //倒数第2个参数
        ExprValue* paraPos = callFunStack->at(lastIndex);

        exprRet->type = EXPR_U16STRING;
        QString ret = pBytes->mid(paraPos->value.vint, paraLen->value.vint);

        exprRet->value.vpoint = new QString(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;



    case qstr_back_Fun:
    {
        exprRet->type = EXPR_WCHAR;
        exprRet->value.vwchar = pBytes->back().unicode();

    }
    break;

    case qstr_toDouble_Fun:
    {
        exprRet->type = EXPR_FLOAT;
        bool ok = true;
        exprRet->value.vfloat = pBytes->toDouble(&ok);

        if (!ok)
        {
            QString msg = QString(u8"警告：行 %1 语句 %2 toDouble 转换失败").arg(curLine).arg(curStatement);
            std::cout << msg.toStdString() << std::endl;
        }
    }
    break;

    case qstr_toFloat_Fun:
    {
        exprRet->type = EXPR_FLOAT;
        bool ok = true;
        exprRet->value.vfloat = pBytes->toFloat(&ok);

        if (!ok)
        {
            QString msg = QString(u8"警告：行 %1 语句 %2 toFloat 转换失败").arg(curLine).arg(curStatement);
            std::cout << msg.toStdString() << std::endl;
        }
    }
    break;

    case qstr_toInt_Fun:
    {
        --lastIndex; //倒数第一个参数
        ExprValue* para1 = callFunStack->at(lastIndex);

        exprRet->type = EXPR_INT;
        bool ok = true;

        if (para1->type == EXPR_INT)
        {
            exprRet->value.vint = pBytes->toInt(&ok, para1->value.vint);

            if (!ok)
            {
                QString msg = QString(u8"警告：行 %1 语句 %2 toInt 转换失败").arg(curLine).arg(curStatement);
                std::cout << msg.toStdString() << std::endl;
            }
        }
    }
    break;

    case qstr_toLongLong_Fun:
    {
        --lastIndex; //倒数第一个参数
        ExprValue* para1 = callFunStack->at(lastIndex);

        exprRet->type = EXPR_INT64;
        bool ok = true;

        if (para1->type == EXPR_INT)
        {
            exprRet->value.vint64 = pBytes->toLongLong(&ok, para1->value.vint);

            if (!ok)
            {
                QString msg = QString(u8"警告：行 %1 语句 %2 toLongLong 转换失败").arg(curLine).arg(curStatement);
                std::cout << msg.toStdString() << std::endl;
            }
        }
    }
    break;

    case qstr_toLower_Fun:
    {
        exprRet->type = EXPR_U16STRING;
        QString ret = pBytes->toLower();

        exprRet->value.vpoint = new QString(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;


    case qstr_toUpper_Fun:
    {
        exprRet->type = EXPR_U16STRING;
        QString ret = pBytes->toUpper();

        exprRet->value.vpoint = new QString(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;


    case qstr_trimmed_Fun:
    {
        exprRet->type = EXPR_U16STRING;
        QString ret = pBytes->trimmed();

        exprRet->value.vpoint = new QString(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;

    case qstr_truncate_Fun:
    {
        isNeedRetValue = false;

        --lastIndex; //倒数第一个参数
        ExprValue* para1 = callFunStack->at(lastIndex);
        pBytes->truncate(para1->value.vint);
    }
    break;

    case qstr_setPosChar_Fun:
    {
        isNeedRetValue = false;

        --lastIndex; //倒数第一个参数
        ExprValue* paraChar = callFunStack->at(lastIndex);

        --lastIndex; //倒数第一个参数
        ExprValue* paraPos = callFunStack->at(lastIndex);

        if (paraPos->value.vint <= pBytes->size() - 1)
        {
            if(paraChar->type == EXPR_WCHAR)
            {
                pBytes->operator[](paraPos->value.vint) = QChar(paraChar->value.vwchar);
            }
            else if(paraChar->type == EXPR_CHAR)
            {
                pBytes->operator[](paraPos->value.vint) = QChar(paraChar->value.vchar);
            }
            else if(paraChar->type == EXPR_INT)
            {
                pBytes->operator[](paraPos->value.vint) = QChar(paraChar->value.vwchar);
            }
            else
            {
                QString msg = QString(u8"警告：行 %1 语句 %2 setPosChar 设置失败，参数2是 %3，需要字符类型!").arg(curLine).arg(curStatement)
                        .arg(getExpeTypeValue(paraChar->type,paraChar));
                //std::cout << msg.toStdString() << std::endl;
                AbortException(msg);
            }
        }
        else
        {
            QString msg = QString(u8"警告：行 %1 语句 %2 setPosChar 设置失败，pos位置值 %3 超过当前字符串长度 %4 (下标从0开始计算)！").arg(curLine).arg(curStatement).arg(paraPos->value.vint).arg(pBytes->size());
            std::cout << msg.toStdString() << std::endl;
        }
    }
    break;


    case qstr_front_Fun:
    {
        exprRet->type = EXPR_WCHAR;
        exprRet->value.vwchar = pBytes->front().unicode();

    }
    break;

    case qstr_isEmpty_Fun:
    {
        exprRet->type = EXPR_BOOL;
        exprRet->value.vbool = pBytes->isEmpty();

    }
    break;

    case qstr_simplified_Fun:
    {
        exprRet->type = EXPR_U16STRING;
        QString ret = pBytes->simplified();
        exprRet->value.vpoint = new QString(std::move(ret));

#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;

    //字符串分割
    case qstr_split_Fun:
    {
        exprRet->type = EXPR_LIST;
        --lastIndex; //倒数第一个参数
        ExprValue* para = callFunStack->at(lastIndex);

        QStringList pList;

        if (para->type == EXPR_WCHAR)
        {
            pList = pBytes->split(QChar(para->value.vwchar));
        }
        else if (para->type == EXPR_CHAR)
        {
            pList = pBytes->split(QChar(para->value.vchar));
        }
        else if (para->type == EXPR_U16STRING)
        {
            //QString str(*pBytes);

            QString * splitStr = (QString*)para->value.vpoint;

            if (!splitStr->isEmpty())
            {
                pList = pBytes->split(*splitStr);
            }
            else
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 split 的分割字符串参数是空字符串，请检查！").arg(curLine).arg(curStatement);
                AbortException(msg);
            }

        }
        else if (para->type == EXPR_STRING)
        {
            //QString str(*pBytes);

            QString splitStr(*(QByteArray*)para->value.vpoint);

            if (!splitStr.isEmpty())
            {
                pList = pBytes->split(splitStr);
            }
            else
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 split 的分割字符串参数是空字符串，请检查！").arg(curLine).arg(curStatement);
                AbortException(msg);
            }

        }
        else
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 split 的参数只能字符或字符串，请检查！").arg(curLine).arg(curStatement);
            AbortException(msg);
        }
        std::vector<ExprValue*>* pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>(pList.size());
#ifdef PIN_MEM_REF
        newTime();
#endif
        exprRet->value.vpoint = pData;

        for (int i = 0, c = pList.size(); i < c; ++i)
        {
            ExprValue* pExpr = new ExprValue();
            pExpr->type = EXPR_U16STRING;
            pExpr->value.vpoint = new QString(std::move(pList[i]));

            pData->operator[](i) = pExpr;
#ifdef PIN_MEM_REF
            newTime(2);
#endif
        }

        //之前说过，凡是返回列表或字典，第一个先不加引用。
        //为什么呢，因为外面把列表expr给变量的时候，都是使用转移方式，而且会加一次addListMapRefNum
        //这里感觉没有完全统一起来。后续可以都加addListMapRefNum，然后exp转移之前，也是否一次。
        //统一了，都要加。

        addListMapRefNum(pData);
    }
    break;

    case qstr_isLower_Fun:
    {
        exprRet->type = EXPR_BOOL;
        exprRet->value.vbool = pBytes->isLower();

    }
    break;


    case qstr_isUpper_Fun:
    {
        exprRet->type = EXPR_BOOL;
        exprRet->value.vbool = pBytes->isUpper();

    }
    break;


    case qstr_indexOf_Fun:
    case qstr_lastIndexOf_Fun:
    {
        //先取出参数个数。
        int callParaNum = lastIndex;

        ExprValue* paraBytes = nullptr;

        int offset = ((fun_info->fun_id == qstr_indexOf_Fun)? 0:-1);
        Qt::CaseSensitivity cs = Qt::CaseSensitive;

        if(callParaNum == 3)
        {
            --lastIndex; //第3个参数
            ExprValue* paraCs = callFunStack->at(lastIndex);
            if(paraCs->type == EXPR_INT || paraCs->type == EXPR_INT64)
            {
                cs = (Qt::CaseSensitivity)paraCs->value.vint;
            }
            else
            {
                paraError(ctx,paraCs,EXPR_INT,3);
            }

            --lastIndex;
            ExprValue* paraOffset = callFunStack->at(lastIndex);
            if(paraOffset->type == EXPR_INT || paraOffset->type == EXPR_INT64)
            {
                offset = paraOffset->value.vint;
            }
            else
            {
                paraError(ctx,paraOffset,EXPR_INT,2);
            }

            --lastIndex;
            paraBytes = callFunStack->at(lastIndex);
        }
        else if(callParaNum == 2)
        {

            --lastIndex;
            ExprValue* paraOffset = callFunStack->at(lastIndex);
            if(paraOffset->type == EXPR_INT || paraOffset->type == EXPR_INT64)
            {
                offset = paraOffset->value.vint;
            }
            else
            {
                paraError(ctx,paraOffset,EXPR_INT,2);
            }

            --lastIndex;
            paraBytes = callFunStack->at(lastIndex);
        }
        else if(callParaNum == 1)
        {
            --lastIndex;
            paraBytes = callFunStack->at(lastIndex);
        }

        exprRet->type = EXPR_INT;
        switch (fun_info->fun_id)
        {

        case qstr_indexOf_Fun:
        {
            if (paraBytes->type == EXPR_U16STRING)
            {
                if (nullptr != paraBytes->value.vpoint)
                {
                    QString* pSrc = (QString*)paraBytes->value.vpoint;

                    exprRet->value.vint = pBytes->indexOf(*pSrc, offset, cs);
                }
                else
                {
                    //其余一律认定没有
                    exprRet->value.vint = -1;
                }
            }
            else if (paraBytes->type == EXPR_STRING)
            {
                if (nullptr != paraBytes->value.vpoint)
                {
                    QString pSrc(*(QByteArray*)paraBytes->value.vpoint);

                    exprRet->value.vint = pBytes->indexOf(pSrc, offset, cs);
                }
                else
                {
                    //其余一律认定没有
                    exprRet->value.vint = -1;
                }
            }
            else if (paraBytes->type == EXPR_WCHAR)
            {
                exprRet->value.vint = pBytes->indexOf(QChar(paraBytes->value.vwchar), offset, cs);
            }
            else if (paraBytes->type == EXPR_CHAR)
            {
                exprRet->value.vint = pBytes->indexOf(QChar(paraBytes->value.vchar), offset, cs);
            }
            else
            {
                //其余一律认定没有
                exprRet->value.vint = -1;
            }

        }
        break;

        case qstr_lastIndexOf_Fun:
        {
            if (paraBytes->type == EXPR_U16STRING)
            {
                if (nullptr != paraBytes->value.vpoint)
                {
                    QString* pSrc = (QString*)paraBytes->value.vpoint;

                    exprRet->value.vint = pBytes->lastIndexOf(*pSrc, offset, cs);
                }
                else
                {
                    //其余一律认定没有
                    exprRet->value.vint = -1;
                }
            }
            else if (paraBytes->type == EXPR_STRING)
            {
                if (nullptr != paraBytes->value.vpoint)
                {
                    QString pSrc(*(QByteArray*)paraBytes->value.vpoint);

                    exprRet->value.vint = pBytes->lastIndexOf(pSrc, offset, cs);
                }
                else
                {
                    //其余一律认定没有
                    exprRet->value.vint = -1;
                }
            }
            else if (paraBytes->type == EXPR_WCHAR)
            {
                exprRet->value.vint = pBytes->lastIndexOf(QChar(paraBytes->value.vwchar), offset, cs);
            }
            else if (paraBytes->type == EXPR_CHAR)
            {
                exprRet->value.vint = pBytes->lastIndexOf(QChar(paraBytes->value.vchar), offset, cs);
            }
            else
            {
                //其余一律认定没有
                exprRet->value.vint = -1;
            }

        }
        break;
        }
    }
        break;
    case qstr_compare_Fun:
    {
        --lastIndex; //第一个参数

        ExprValue* paraCs = callFunStack->at(lastIndex);

        --lastIndex;
        ExprValue* paraBytes = callFunStack->at(lastIndex);

        exprRet->type = EXPR_INT;

        switch (fun_info->fun_id)
        {
        case qstr_compare_Fun:
        {
            if (nullptr != paraBytes->value.vpoint)
            {
                if(paraBytes->type == EXPR_U16STRING)
                {
                    QString* pSrc = (QString*)paraBytes->value.vpoint;

                    exprRet->value.vint = pBytes->compare(*pSrc, (Qt::CaseSensitivity)paraCs->value.vint);
                }
                else if(paraBytes->type == EXPR_STRING)
                {
                    QString pSrc(*(QByteArray*)paraBytes->value.vpoint);

                    exprRet->value.vint = pBytes->compare(pSrc, (Qt::CaseSensitivity)paraCs->value.vint);
                }
                else if(paraBytes->type == EXPR_WCHAR)
                {
                    QString pSrc((QChar)paraBytes->value.vwchar);

                    exprRet->value.vint = pBytes->compare(pSrc, (Qt::CaseSensitivity)paraCs->value.vint);
                }
                else if(paraBytes->type == EXPR_CHAR)
                {
                    QString pSrc((QChar)paraBytes->value.vchar);

                    exprRet->value.vint = pBytes->compare(pSrc, (Qt::CaseSensitivity)paraCs->value.vint);
                }
                else
                {
                    QString err = QString("错误：行号 %1 语句 %2 类型是 %3 ，无法和string对比").arg(curLine).arg(curStatement).arg(getExpeTypeValue(paraBytes->type));
                }
            }
            else if (pBytes->size() == 0) //都是空
            {
                //如果都是空，咋办，认定相等。
                exprRet->value.vint = 0;
            }
            else
            {
                //原始不为空，原始大。
                exprRet->type = 0;
                exprRet->value.vint = 1;
            }
        }
        break;
        }
    }
    break;

    case qstr_insert_Fun:
    {
        --lastIndex; //第一个参数

        ExprValue* insertStr = callFunStack->at(lastIndex);

        --lastIndex;
        ExprValue* pos = callFunStack->at(lastIndex);

        exprRet->type = EXPR_U16STRING;

        isNeedRetValue = false;

        if (insertStr->type == EXPR_U16STRING)
        {
            if (nullptr != insertStr->value.vpoint)
            {
                QString* pSrc = (QString*)insertStr->value.vpoint;

                pBytes->insert(pos->value.vint, *pSrc);
            }
        }
        else if (insertStr->type == EXPR_STRING)
        {
            if (nullptr != insertStr->value.vpoint)
            {
                QString pSrc(*(QByteArray*)insertStr->value.vpoint);

                pBytes->insert(pos->value.vint, pSrc);
            }
        }
        else if (insertStr->type == EXPR_WCHAR)
        {
            pBytes->insert(pos->value.vint, QChar(insertStr->value.vwchar));

        }
        else if (insertStr->type == EXPR_CHAR)
        {
            pBytes->insert(pos->value.vint, QChar(insertStr->value.vchar));

        }
        else
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 insert 的参数类型是 %3，需要字符串或字符类型，请检查！").arg(curLine).arg(curStatement).arg(getExpeTypeValue(insertStr->type,insertStr));
            AbortException(msg);
        }

    }
    break;

    case qstr_clear_Fun:
    {
        isNeedRetValue = false;
        pBytes->clear();
    }
    break;

    }

    if (hasError != 0)
    {

        ExprValue* funName = callFunStack->last();

        std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();
        int lastIndex = callFunStack->size() - 1;
        ExprValue* obj = callFunStack->at(--lastIndex);

        switch (hasError)
        {
        case 1:
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 的参数只能整数类型，请检查！").arg(curLine).arg(curStatement).arg(QStr(name));
            AbortException(msg);
        }
        break;
        case 2:
        {
            QString msg = QString(u8"错误：行号 %1 函数 %2 语句 %3 类名 %4 调用全局函数 %5 错误，u16 字符串类型名只能是 string ！").arg(curLine).arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(name));
            AbortException(msg);
        }
        break;
        }

    }

    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }

    return 0;
}


int qstring_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

    ExprValue* errorPara = nullptr;

    switch (fun_info->fun_id)
    {

    //从字符串获取qstring
    case qstr_fromZfc_Fun:
    {
        ExprValue* obj = callFunStack->at(lastIndex);
        if (obj->type == EXPR_GLOBAL_PACKNAME)
        {

            if (obj->value.vpacktype == EXPR_U16STRING)
            {

                switch (fun_info->fun_id)
                {
                    //字符串转qstring
                    case qstr_fromZfc_Fun:
                    {
                        --lastIndex;
                        ExprValue* paraZfc = callFunStack->at(lastIndex);
                        exprRet->type = EXPR_U16STRING;
                        exprRet->value.vpoint = new QString(*(QByteArray*)paraZfc->value.vpoint);
                        #ifdef PIN_MEM_REF
                                newTime();
                        #endif

                    }
                    break;
                }
            }
        }
    }
    break;

    case qstring_toZfc_Fun:
    {
         ExprValue* obj = callFunStack->at(lastIndex);
         exprRet->type = EXPR_STRING;

         exprRet->value.vpoint = new QByteArray(((QString*)obj->value.vpoint)->toUtf8());
        #ifdef PIN_MEM_REF
                 newTime();
        #endif
    }
        break;

        //翻译为一个一个的字符，给LIST去处理。这样可以一个一个汉字的去处理。
    case getCharList_Fun:
    {
        ExprValue* obj = callFunStack->at(lastIndex);

        exprRet->type = EXPR_LIST;

        const QString& qstr = *(QString*)obj->value.vpoint;

        std::vector<ExprValue*>* pData = new std::vector<ExprValue*>(qstr.size());
#ifdef PIN_MEM_REF
        newTime();
#endif
        exprRet->value.vpoint = pData;
        addListMapRefNum(pData);


        for (int i = 0, c = pData->size(); i < c; ++i)
        {
            ExprValue* pExpr = new ExprValue();
            pExpr->type = EXPR_WCHAR;
            pExpr->value.vwchar = qstr.at(i).unicode();
#ifdef PIN_MEM_REF
            newTime();
#endif
            pData->operator[](i) = pExpr;

        }

    }
    break;

    case qstr_size_Fun:
    case qstr_at_Fun:
    {
        ExprValue* obj = callFunStack->at(lastIndex);

        switch (fun_info->fun_id)
        {
            case qstr_size_Fun:
            {
                exprRet->type = EXPR_INT;
                exprRet->value.vint = obj->getU16String()->size();
            }
                break;

            case qstr_at_Fun:
            {
                --lastIndex;
                ExprValue* pExprIndex = callFunStack->at(lastIndex);

                exprRet->type = EXPR_WCHAR;
                exprRet->value.vwchar = obj->getU16String()->at(pExprIndex->value.vint).unicode();
            }
            break;
        default:
            break;
        }
    }
    break;

    }

    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }
    return 0;
}


bool compareExpr(ExprValue* a, ExprValue* b) {

    return LESS_STATUS == CompareExprAndExpr(*a, *b, false);
}

bool compareNotLessExpr(ExprValue* a, ExprValue* b) {

    return LESS_STATUS != CompareExprAndExpr(*a, *b, false);
}

int list_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

    ExprValue* errorPara = nullptr;

    switch (fun_info->fun_id)
    {
        //静态函数
    case lb_create_Fun:
    {
        ExprValue* obj = callFunStack->at(lastIndex);
        if (obj->type == EXPR_GLOBAL_PACKNAME)
        {
            if (obj->value.vpacktype == EXPR_LIST)
            {
                //创建一个列表
                --lastIndex;
                ExprValue* para2 = callFunStack->at(lastIndex);

                --lastIndex;
                ExprValue* para1 = callFunStack->at(lastIndex);

                if ((para1->type == EXPR_INT || para1->type == EXPR_INT64) && (para2->type != EXPR_MAP))
                {
                    exprRet->type = EXPR_LIST;


                    std::vector<ExprValue*>* pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>(para1->value.vint);
#ifdef PIN_MEM_REF
                    newTime();
#endif
                    exprRet->value.vpoint = pData;

                    //if (para2->type == EXPR_INT)
                    {
                        for (int i = 0, c = pData->size(); i < c; ++i)
                        {
                            pData->operator[](i) = para2->deepCopy2();

                            /*ExprValue* pExpr = new ExprValue();
                            pExpr->type = EXPR_INT;
                            pExpr->value.vint = para2->value.vint;

                            pData->operator[](i) = pExpr;
#ifdef PIN_MEM_REF
                            newTime();
#endif*/
                        }
                    }
#if 0
                    else if (para2->type == EXPR_STRING)
                    {
                        for (int i = 0, c = pData->size(); i < c; ++i)
                        {
                            ExprValue* pExpr = new ExprValue();
                            pExpr->type = EXPR_STRING;
                            pExpr->value.vpoint = new QByteArray(*(QByteArray*)para2->value.vpoint);

                            pData->operator[](i) = pExpr;
#ifdef PIN_MEM_REF
                            newTime(2);
#endif
                        }
                    }
#endif
                    addListMapRefNum(pData);
                }
                else
                {
                    ExprValue* funName = callFunStack->last();

                    std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

                    QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 参数无法匹配，请检查！").arg(curLine).arg(curStatement).arg(QStr(name));

                    AbortException(msg);
                }
            }
            else
            {
                ExprValue* funName = callFunStack->last();

                std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

                QString msg = QString(u8"错误：行号 %1 语句 %2 函数 %3 只能使用类型名 lb 调用！").arg(curLine).arg(curStatement).arg(QStr(name));

                AbortException(msg);
            }

        }
    }
        break;
        //获取列表大小
        case lb_size_Fun:
        case lb_append_Fun:
        case lb_at_Fun:
        case lb_last_Fun:
        case lb_first_Fun:
        case lb_isEmpty_Fun:
        case lb_clear_Fun:
        case lb_insert_Fun:
        case lb_indexOf_Fun:
        case lb_lastIndexOf_Fun:
        case lb_mid_Fun:
        case lb_copy_Fun:
        case lb_removeAt_Fun:
        case lb_takeAt_Fun:
        case lb_takeFirst_Fun:
        case lb_takeLast_Fun:
        case lb_swapItemsAt_Fun:
        case lb_reserve_Fun:
        case lb_sort_Fun:
        case lb_sortStruct_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                std::vector<ExprValue*>* pList = getListFromExpr(obj);
                if (pList != nullptr)
                {
                    switch(fun_info->fun_id)
                    {
                        case lb_size_Fun:
                        {
                            exprRet->type = EXPR_INT;
                            exprRet->value.vint = pList->size();
                        }
                        break;

                        case lb_at_Fun:
                        {
                            --lastIndex;
                            ExprValue* para = callFunStack->at(lastIndex);

                            if(para->value.vint >= 0 && para->value.vint < pList->size())
                            {
                                ExprValue* pRet = pList->at(para->value.vint);

                                exprRet->type = pRet->type;

                                //就算深拷贝，文件，列表，字典还是浅拷贝。
                                *exprRet = pRet->deepCopy();
                            }
                            else
                            {
                                QString msg = QString(u8"错误：行号 %1 语句 %2 列表越界访问，列表有%3个元素，当前访问下标是 %4").arg(curLine).arg(curStatement)
                                                  .arg(pList->size()).arg(para->value.vint);
                                AbortException(msg);
                            }
                        }
                        break;

                        case lb_last_Fun:
                        case lb_first_Fun:
                        {
                            if (pList->size() > 0)
                            {
                                ExprValue* pRet = (fun_info->fun_id == lb_last_Fun) ? pList->back() : pList->front();
                                exprRet->type = pRet->type;
                                //就算深拷贝，文件，列表，字典还是浅拷贝。
                                *exprRet = pRet->deepCopy();
                            }
                            else
                            {
                                exprRet->type = EXPR_ERR;
                                QString msg = QString(u8"错误：行号 %1 语句 %2 列表越界访问，列表为空，没有任何一个元素！").arg(curLine).arg(curStatement);
                                AbortException(msg);
                            };

                        }
                        break;

                        case lb_isEmpty_Fun:
                        {
                            exprRet->type = EXPR_BOOL;
                            exprRet->value.vbool = pList->empty();
                        }
                        break;

                        case lb_clear_Fun:
                        {
                            isNeedRetValue = false;

                            //这里很关键，注意注释不删。这里没必要通过名称获取原始变量。
                            //因为可能是链式调用，需要的可能反而是一个中间变量，此时中间变量的varName反而可能是一个函数名称。
                            //这样是不对的。其实lb本身已经是引用获取的，直接获取引用的值，就是对应的调用者原始变量的值本身了。
                            #if 0 
                                //获取变量本身
                                SymNode* pSym = getVarFromSymTable(*(obj->varName), ctx);
                                pSym->destory();

                                //不能为空，要初始化为空列表
                                pSym->value.vpoint = new std::vector<ExprValue*>(0);
                                addListMapRefNum(pSym->value.vpoint);
                                #ifdef PIN_MEM_REF
                                                            newTime();
                                #endif
                            #endif
                            //这个obj->value.vpoint就是原始调用者本身的值，而且是引用来的，直接修改即可。
                            //原始调用者可能是一个变量，也可能是链式调用返回值（中间变量）。

                            if (obj->value.vpoint != nullptr)
                            {
                                obj->doClearList();
                            }
                        }
                        break;

                        case lb_insert_Fun:
                        {
                            isNeedRetValue = false;

                            --lastIndex;
                            ExprValue* para2 = callFunStack->at(lastIndex);

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            if ((para1->type == EXPR_INT || para1->type == EXPR_INT64 )&&( para1->value.vint >= 0 ))
                            {
                                //列表不能插入字典。
                                if (isPinListVar(para1->type))
                                {
                                    //超过列表最后一个位置，直接尾部插入即可
                                    if (para1->value.vint >= pList->size())
                                    {
                                        pList->push_back(para2->shallowMoveCopy());
                                    }
                                    else
                                    {
                                        //找到位置后插入
                                        pList->insert(pList->begin() + para1->value.vint, para2->shallowMoveCopy());
                                    }
                                }
                                else
                                {
                                    errorPara = para1;
                                    hasError = 1;
                                }
                            }
                            else
                            {
                                ExprValue* funName = callFunStack->last();

                                std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

                                QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 参数无法匹配！").arg(curLine).arg(curStatement).arg(QStr(name));

                                AbortException(msg);
                            }
                        }
                        break;

                        case lb_append_Fun:
                        {
                            isNeedRetValue = false;
                            int paraNum = lastIndex;

                            ExprValue* para = nullptr;
                            ExprValue* paraListWay = nullptr;

                            if (paraNum == 1)
                            {
                            //获取第一个参数
                            --lastIndex;
                                para = callFunStack->at(lastIndex);
                            }
                            else if (paraNum == 2)
                            {
                                --lastIndex;
                                paraListWay = callFunStack->at(lastIndex);

                                //获取第一个参数
                                --lastIndex;
                                para = callFunStack->at(lastIndex);
                            }

                            //不能是字典，函数。
                            if(isPinListVar(para->type))
                            {
                                //这里的元素可能是文件、字符串、所以这里要加计数
                                //addListMapRefNum(*para);这里不需要加，因为para已经被掏空，外面不需要删除。等于是转移计数。
                                if (para->type != EXPR_LIST)
                                {
                                pList->push_back(para->shallowMoveCopy());
                                }
                                else
                                {
                                        //如果是列表，则需要判断第2个参数。
                                        if (paraListWay != nullptr && paraListWay->type == EXPR_INT && paraListWay->value.vint == 1)
                                        {

                                            //如果参数2值是1，则按照分解开列表元素插入
                                            std::vector<ExprValue*>* pData = (std::vector<ExprValue*>*)para->value.vpoint;
                                            if (pData != nullptr && pData->size() > 0)
                                            {
                                                for (int i = 0; i < pData->size(); ++i)
                                                {
                                                    pList->push_back(pData->at(i)->deepCopy2());
                                                }
                                            }
                                        }
                                        else
                                        {
                                            //默认把列表做整体加入。
                                            pList->push_back(para->shallowMoveCopy());
                                        }

                                }
                            }
                            else
                            {
                                hasError = 1;

                                errorPara = para;
                            }
                        }
                        break;

                        case lb_indexOf_Fun:
                        {
                            //1到2个参数
                             //先取出参数个数。
                            int callParaNum = lastIndex;

                            int pos = 0;

                            if (2 == callParaNum)
                            {
                                --lastIndex;
                                ExprValue* para2 = callFunStack->at(lastIndex);
                                if (para2->type == EXPR_INT || para2->type == EXPR_INT64)
                                {
                                    pos = para2->value.vint;
                                }

                                --callParaNum;
                            }

                            //1个参数
                            if (1 == callParaNum)
                            {
                                --lastIndex;
                                ExprValue* para1 = callFunStack->at(lastIndex);


                                //只能支持整数和字符串、字符的查找。
                                if (para1->type == EXPR_INT || para1->type == EXPR_INT64)
                                {
                                    exprRet->type = EXPR_INT;
                                    exprRet->value.vint = -1;

                                    for (int i = pos, c = pList->size(); i < c; ++i)
                                    {
                                        ExprValue* pExer = pList->operator[](i);
                                        if (pExer->type == EXPR_INT && pExer->value.vint == para1->value.vint64)
                                        {

                                            exprRet->value.vint = i;
                                            break;
                                        }
                                        else if (pExer->type == EXPR_INT64 && pExer->value.vint64 == para1->value.vint64)
                                        {

                                            exprRet->value.vint = i;
                                            break;
                                        }
                                    }
                                }
                                else if (para1->type == EXPR_STRING)
                                {
                                    exprRet->type = EXPR_INT;
                                    exprRet->value.vint = -1;

                                    for (int i = pos, c = pList->size(); i < c; ++i)
                                    {
                                        ExprValue* pExer = pList->operator[](i);
                                        if (pExer->type == EXPR_STRING && (*(QByteArray*)pExer->value.vpoint == *(QByteArray*)para1->value.vpoint))
                                        {
                                            exprRet->value.vint = i;
                                            break;
                                        }

                                    }
                                }
                                else if (para1->type == EXPR_CHAR)
                                {
                                    exprRet->type = EXPR_INT;
                                    exprRet->value.vint = -1;

                                    for (int i = pos, c = pList->size(); i < c; ++i)
                                    {
                                        ExprValue* pExer = pList->operator[](i);
                                        if (pExer->type == EXPR_CHAR && (pExer->value.vchar == para1->value.vchar))
                                        {
                                            exprRet->value.vint = i;
                                            break;
                                        }

                                    }
                                }

                            }
                            else
                            {
                                QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 indexOf 参数个数或参数形式无法匹配！该函数只能查找整数、字符、字符串！").arg(curLine).arg(curStatement);

                                AbortException(msg);
                            }

                        }
                        break;

                        case lb_lastIndexOf_Fun:
                        {
                            //1到2个参数
                             //先取出参数个数。
                            int callParaNum = lastIndex;

                            int pos = pList->size() - 1;

                            if (2 == callParaNum)
                            {
                                --lastIndex;
                                ExprValue* para2 = callFunStack->at(lastIndex);
                                if (para2->type == EXPR_INT || para2->type == EXPR_INT64)
                                {
                                    pos = para2->value.vint;

                                    if (para2->value.vint < 0 )
                                    {
                                        pos = pList->size() + para2->value.vint;
                                    }
                                    else if (pos >= pList->size())
                                    {
                                        pos = pList->size() - 1;
                                    }
                                }

                                --callParaNum;
                            }

                            //1个参数
                            if (1 == callParaNum)
                            {
                                --lastIndex;
                                ExprValue* para1 = callFunStack->at(lastIndex);
                               // int ret = -1;

                                //只能支持整数和字符串的查找。
                                if (para1->type == EXPR_INT || para1->type == EXPR_INT64)
                                {
                                    exprRet->type = EXPR_INT;
                                    exprRet->value.vint = -1;

                                    for (int i = pos; i >= 0; --i)
                                    {
                                        ExprValue* pExer = pList->operator[](i);
                                        if (pExer->type == EXPR_INT && pExer->value.vint == para1->value.vint64)
                                        {

                                            exprRet->value.vint = i;
                                            break;
                                        }
                                        else if (pExer->type == EXPR_INT64 && pExer->value.vint64 == para1->value.vint64)
                                        {

                                            exprRet->value.vint = i;
                                            break;
                                        }
                                    }
                                }
                                else if (para1->type == EXPR_STRING)
                                {
                                    exprRet->type = EXPR_INT;
                                    exprRet->value.vint = -1;

                                    for (int i = pos; i >= 0; --i)
                                    {
                                        ExprValue* pExer = pList->operator[](i);
                                        if (pExer->type == EXPR_STRING && (*(QByteArray*)pExer->value.vpoint == *(QByteArray*)para1->value.vpoint))
                                        {
                                            exprRet->value.vint = i;
                                            break;
                                        }

                                    }
                                }
                                else if (para1->type == EXPR_CHAR)
                                {
                                    exprRet->type = EXPR_INT;
                                    exprRet->value.vint = -1;

                                    for (int i = pos; i >= 0; --i)
                                    {
                                        ExprValue* pExer = pList->operator[](i);
                                        if (pExer->type == EXPR_CHAR && (pExer->value.vchar == para1->value.vchar))
                                        {
                                            exprRet->value.vint = i;
                                            break;
                                        }

                                    }
                                }

                            }
                            else
                            {
                                QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 lastIndexOf 参数个数或参数形式无法匹配！该函数只能查找整数或字符串！").arg(curLine).arg(curStatement);

                                AbortException(msg);
                            }

                        }
                        break;

                        case lb_mid_Fun:
                        {
                            --lastIndex;
                            ExprValue* para2 = callFunStack->at(lastIndex);

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            int start = para1->value.vint;
                            if (start < 0)
                            {
                                start = 0;
                            }

                            //如果第二个是是-1，表示往后所有
                            if (para2->value.vint < 0)
                            {
                                para2->value.vint = pList->size();
                            }


                            int end = start + para2->value.vint;

                            if (end > pList->size())
                            {
                                end = pList->size();
                            }

                            exprRet->type = EXPR_LIST;

                            std::vector<ExprValue*>* pData = new std::vector<ExprValue*>(end - start);
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            exprRet->value.vpoint = pData;
                            addListMapRefNum(pData);

                            if (para2->value.vint == 0)
                            {
                                QString msg = QString(u8"警告：行号 %1 语句 %2 调用函数 第二个参数是 %3，返回空列表！").arg(curLine).arg(curStatement).arg(para2->value.vint);
                                std::cout << msg.toStdString() << std::endl;
                            }
                            else
                            {
                                for (int i = start,j=0; i < end; ++i,++j)
                                {
                                    ExprValue* pSrcExpr = pList->at(i);
                                    ExprValue* pNewExpr = pSrcExpr->deepCopy2();
                                    pData->operator[](j) = pNewExpr;
                                }
                            }

                        }
                        break;

                        //对列表进行copy操作，这个copy是真正的深拷贝，而不是引用拷贝。切记。
                        case lb_copy_Fun:
                        {
                            exprRet->type = EXPR_LIST;

                            std::vector<ExprValue*>* pData = new std::vector<ExprValue*>(pList->size());
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            exprRet->value.vpoint = pData;
                            addListMapRefNum(pData);

                            for (int i = 0, c = pList->size(); i < c; ++i)
                            {
                                ExprValue* pSrcExpr = pList->at(i);
                                ExprValue* pNewExpr = pSrcExpr->deepCopy2(true);
                                pData->operator[](i) = pNewExpr;
                            }

                        }
                        break;

                        case lb_removeAt_Fun:
                        {
                            isNeedRetValue = false;

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);
                            if (para1->value.vint >= 0 && para1->value.vint < pList->size())
                            {
                                auto it = pList->begin() + para1->value.vint;

                                (*it)->freeMem();
                                delete (*it);
#ifdef PIN_MEM_REF
                                freeTimes++;
#endif
                                pList->erase(it);
                            }
                            else
                            {
                                ExprValue* funName = callFunStack->last();

                                std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

                                QString msg = QString(u8"警告：行号 %1 语句 %2 调用函数 %3 删除下标位置 %4 元素位置越界，列表长度%5， 没有删除！").arg(curLine).arg(curStatement).arg(QStr(name)).arg(para1->value.vint).arg(pList->size());
                                std::cout << msg.toStdString() << std::endl;
                            }
                        }
                        break;


                        case lb_takeAt_Fun:
                        {

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);
                            if (para1->value.vint >= 0 && para1->value.vint < pList->size())
                            {
                                auto it = pList->begin() + para1->value.vint;

                                //这里是直接把二者浅拷贝，然后计数不增不减，等于是做了转移。
                                *exprRet = *(*it);

                                delete (*it);
#ifdef PIN_MEM_REF
                                freeTimes++;
#endif
                                pList->erase(it);
                            }
                            else
                            {
                                ExprValue* funName = callFunStack->last();

                                std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

                                QString msg = QString(u8"警告：行号 %1 语句 %2 调用函数 %3 删除下标位置 %4 元素位置越界，列表长度%5， 没有删除！").arg(curLine).arg(curStatement).arg(QStr(name)).arg(para1->value.vint).arg(pList->size());
                                std::cout << msg.toStdString() << std::endl;

                                exprRet->type = EXPR_INT;
                                exprRet->value.vint = -1;
                            }
                        }
                        break;

                        case lb_takeFirst_Fun:
                        case lb_takeLast_Fun:
                        {
                            if (pList->size() > 0)
                            {
                                int pos = 0;
                                if (fun_info->fun_id == lb_takeLast_Fun)
                                {
                                    pos = pList->size() - 1;
                                }

                                auto it = pList->begin() + pos;

                                //这里是直接把二者浅拷贝，然后计数不增不减，等于是做了转移。
                                *exprRet = *(*it);

                                delete (*it);
#ifdef PIN_MEM_REF
                                freeTimes++;
#endif
                                pList->erase(it);
                            }
                            else
                            {
                                ExprValue* funName = callFunStack->last();

                                std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

                                QString msg = QString(u8"警告：行号 %1 语句 %2 调用函数 %3 位置越界，列表是空，没有删除！").arg(curLine).arg(curStatement).arg(QStr(name));
                                std::cout << msg.toStdString() << std::endl;

                                exprRet->type = EXPR_INT;
                                exprRet->value.vint = -1;
                            }
                        }
                        break;

                        case lb_swapItemsAt_Fun:
                        {
                            isNeedRetValue = false;

                            --lastIndex;
                            ExprValue* para2 = callFunStack->at(lastIndex);

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            if (para1->value.vint >= 0 && para1->value.vint < pList->size() && para2->value.vint >= 0 && para2->value.vint < pList->size())
                            {
                                std::swap((*pList)[para1->value.vint], (*pList)[para2->value.vint]);
                            }
                            else
                            {
                                ExprValue* funName = callFunStack->last();
                                std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

                                QString msg = QString(u8"警告：行号 %1 语句 %2 调用函数 %3 位置越界！").arg(curLine).arg(curStatement).arg(QStr(name));
                                std::cout << msg.toStdString() << std::endl;
                            }
                        }
                        break;

                        case lb_reserve_Fun:
                        {
                            isNeedRetValue = false;

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            pList->reserve(para1->value.vint);
                        }
                        break;

                        //列表排序。只能对整数、字符串进行排序。
                        case lb_sort_Fun:
                        case lb_sortStruct_Fun:
                        {
                            //默认0 升序排序。1降序。
                            isNeedRetValue = false;

                            //2个以上才需要排序。
                            if (pList->size() >=2 )
                            {
                                int type = -1;
                                bool canStructEleSort = true;

                                for (std::vector<ExprValue*>::iterator it = pList->begin(); it != pList->end(); ++it)
                                {
                                    //必须都是整数、小数、字符、或者字符串。
                                    if (type == -1)
                                    {
                                        type = (*it)->type;
                                    }
                                    else if (type != (*it)->type)
                                    {
                                        QString msg = QString(u8"错误：行号 %1 语句 %2 列表无法正确排序，因为列表中掺杂有不同类型的元素，排序结果不一定正确").arg(curLine).arg(curStatement);
                                        std::cout << msg.toStdString() << std::endl;

                                        //如果是按结构体排序，则报错，因为有不同的结构体。
                                        if (fun_info->fun_id == lb_sortStruct_Fun)
                                        {
                                            AbortException(msg);
                                        }
                                        canStructEleSort = false;
                                        break;
                                    }
                                }

                                if(fun_info->fun_id == lb_sort_Fun)
                                {
                                    --lastIndex;
                                    ExprValue* para1 = callFunStack->at(lastIndex);

                                    if (0 == para1->value.vint)
                                    {
                                        std::sort(pList->begin(), pList->end(), compareExpr);
                                    }
                                    else
                                    {
                                        std::sort(pList->begin(), pList->end(), compareNotLessExpr);
                                    }
                            }
                                else if(fun_info->fun_id == lb_sortStruct_Fun)
                                {
                                    //如果是结构体，则可以按照结构体中的某一个元素进行排序
                                    if (type == EXPR_STRUCT && canStructEleSort)
                                    {
                                        --lastIndex;
                                        ExprValue* para1 = callFunStack->at(lastIndex);

                                        --lastIndex;
                                        ExprValue* paraStructIndex = callFunStack->at(lastIndex);

                                        int index = paraStructIndex->value.vint;


                                        //做一次参数检查。看序号是否超过结构体的范围。
                                        STRUCT_VALUE_DATA* pA = (STRUCT_VALUE_DATA*)pList->at(0)->value.vpoint;
                                        std::vector<ExprValue*>* pAVec = (std::vector<ExprValue*>*)pA->pValue;
                                        if (pAVec == nullptr || index < 0 || index >= pAVec->size())
                                        {
                                            QString msg = QString(u8"错误：行号 %1 语句 %2 列表元素结构体没有对应序号 %3 的元素，按其排序").arg(curLine).arg(curStatement)
                                                .arg(index);
                                            AbortException(msg);
                        }

                                        if (0 == para1->value.vint)
                                        {

                                            std::sort(pList->begin(), pList->end(), [index](ExprValue* a, ExprValue* b) {

                                                STRUCT_VALUE_DATA* pA = (STRUCT_VALUE_DATA*)a->value.vpoint;
                                                std::vector<ExprValue*>* pAVec = (std::vector<ExprValue*>*)pA->pValue;

                                                STRUCT_VALUE_DATA* pB = (STRUCT_VALUE_DATA*)b->value.vpoint;
                                                std::vector<ExprValue*>* pBVec = (std::vector<ExprValue*>*)pB->pValue;

                                                 return compareExpr(pAVec->at(index), pBVec->at(index));

                                                });
                                        }
                                        else
                                        {
                                            std::sort(pList->begin(), pList->end(), [index](ExprValue* a, ExprValue* b) {

                                                STRUCT_VALUE_DATA* pA = (STRUCT_VALUE_DATA*)a->value.vpoint;
                                                std::vector<ExprValue*>* pAVec = (std::vector<ExprValue*>*)pA->pValue;

                                                STRUCT_VALUE_DATA* pB = (STRUCT_VALUE_DATA*)b->value.vpoint;
                                                std::vector<ExprValue*>* pBVec = (std::vector<ExprValue*>*)pB->pValue;

                                                return compareNotLessExpr(pAVec->at(index), pBVec->at(index));

                                                });
                                        }
                                    }

                                }
                            }
                        }
                        break;
                    }
                }
            }
        }
        break;
    }

    if (hasError > 0)
    {
        if(hasError == 1)
        {
            ExprValue* funName = callFunStack->last();

            std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

            QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 不能把 %4 加入到列表中。").arg(curLine).arg(curStatement).arg(QStr(name)).arg(getExpeTypeValue(errorPara->type));

            AbortException(msg);
        }
    }
    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }
    return 0;
}

int map_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

    ExprValue* errorPara = nullptr;

    switch (fun_info->fun_id)
    {

        case zd_clear_Fun:
        case zd_size_Fun:
        case zd_isEmpty_Fun:
        case zd_contains_Fun:
        case zd_remove_Fun:
        case zd_keys_Fun:
        case zd_value_Fun:
        case zd_copy_Fun:
        {

            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj != nullptr)
            {
                std::unordered_map<ExprValue, ExprValue*>* pMap = getMapFromExpr(obj);
                if (pMap != nullptr)
                {
                    switch (fun_info->fun_id)
                    {
                        case zd_clear_Fun:
                        {
                            isNeedRetValue = false;

#if 0
                            //获取变量本身
                            SymNode* pSym = getVarFromSymTable(*(obj->varName), ctx);
                            pSym->destory();

                            //不能为空，要初始化为空列表
                            pSym->value.vpoint = new std::unordered_map<ExprValue, ExprValue*>();
                            addListMapRefNum(pSym->value.vpoint);
#ifdef PIN_MEM_REF
                            newTime();
#endif
#endif
                            //具体说明见lb_clear_Fun.
                            if (obj->value.vpoint != nullptr)
                            {
                                obj->doClearMap();
                            }
                        }
                        break;

                        case zd_size_Fun:
                        {
                            exprRet->type = EXPR_INT;
                            exprRet->value.vint = pMap->size(); 
                        }
                        break;

                        case zd_isEmpty_Fun:
                        {
                            exprRet->type = EXPR_BOOL;
                            exprRet->value.vbool = (pMap->size()==0);
                        }
                        break;

                        case zd_contains_Fun:
                        {
                            exprRet->type = EXPR_BOOL;

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            if (para1->type == EXPR_INT || para1->type == EXPR_INT64 || para1->type == EXPR_STRING)
                            {
                                auto it = pMap->find(*para1);
                                exprRet->value.vbool = (it != pMap->end());
                            }
                            else
                            {
                                //不符合的一律查找不到。
                                exprRet->value.vbool = false;
                            }

                        }
                        break;

                        case zd_value_Fun:
                        {

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            if (para1->type == EXPR_INT || para1->type == EXPR_INT64 || para1->type == EXPR_STRING)
                            {
                                auto it = pMap->find(*para1);
                                if (it != pMap->end())
                                {
                                    *exprRet = ((ExprValue*)(it->second))->deepCopy();
                                }
                            }
                            else
                            {
                                QString msg = QString(u8"错误：行号 %1 语句 %2 字典 %3 不存在key 值 %4 。").arg(curLine).arg(curStatement).arg(QStr(*(obj->varName))).arg(para1->toString());

                                AbortException(msg);
                            }
                        }
                        break;

                        //按key删除。
                        case zd_remove_Fun:
                        {
                            exprRet->type = EXPR_BOOL;
                            exprRet->value.vbool = false;

                            --lastIndex;
                            ExprValue* para1 = callFunStack->at(lastIndex);

                            if (para1->type == EXPR_INT || para1->type == EXPR_INT64 || para1->type == EXPR_STRING)
                            {
                                auto it = pMap->find(*para1);
                                if (it != pMap->end())
                                {
                                    it->second->freeMem();

                                    delete it->second;
#ifdef PIN_MEM_REF
                                    freeTimes++;
#endif
                                    ((ExprValue)(it->first)).freeMem();

                                    // 移除键值对
                                    pMap->erase(it);
                                    exprRet->value.vbool = true;
                                }
                            }  
                        }
                        break;

                        //返回所有keys
                        case zd_keys_Fun:
                        {
                            exprRet->type = EXPR_LIST;

                            std::vector<ExprValue*>* pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>(pMap->size());
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            exprRet->value.vpoint = pData;
                            addListMapRefNum(pData);

                            int i = 0;
                            for (const auto& pair : *pMap) { // 遍历键值对

                                (*pData)[i++] = ((ExprValue)pair.first).deepCopy2();

                            }

                        }
                        break;

                        case zd_copy_Fun:
                        {
                            exprRet->type = EXPR_MAP;

                            std::unordered_map<ExprValue, ExprValue*>* pNewMap = new std::unordered_map<ExprValue, ExprValue*>();
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            addListMapRefNum(pNewMap);
                            exprRet->value.vpoint = pNewMap;

                            for (std::unordered_map<ExprValue, ExprValue*>::iterator it = pMap->begin(); it != pMap->end(); ++it)
                            {
                                ExprValue keyCopy(it->first);

                                pNewMap->insert({ keyCopy.deepCopy(), (it->second)->deepCopy2(true)});
                            }
                        }
                        break;
                    }
                }
            }

        }
            break;
    }

    if (hasError > 0)
    {
        if (hasError == 1)
        {
            ExprValue* funName = callFunStack->last();

            std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

            QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 不能把 %4 加入到字典中。").arg(curLine).arg(curStatement).arg(QStr(name)).arg(getExpeTypeValue(errorPara->type));

            AbortException(msg);
        }
    }
    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }
    return 0;
}

void initListFunTab()
{
    if (!s_list_fun_sys_load)
    {
        s_list_fun_sys_load = true;

        s_register_call_back_fun = list_fun_cpp;
        s_register_pack_id = EXPR_LIST;

        register_cpp_fun(lb_size_Fun, "lb_size", {});

        register_cpp_fun(lb_append_Fun, "lb_append", {1,2,EXPR_PARA_DYNANIC});

        register_cpp_fun(lb_at_Fun, "lb_at", {EXPR_INT});

        register_cpp_fun(lb_last_Fun, "lb_last", { });

        register_cpp_fun(lb_first_Fun, "lb_first", { });



        register_cpp_fun(lb_isEmpty_Fun, "lb_isEmpty", { });

        register_cpp_fun(lb_clear_Fun, "lb_clear", { });

        //插入，变参，需要2个参数。
        register_cpp_fun(lb_insert_Fun, "lb_insert", { 2,2,EXPR_PARA_DYNANIC });

        register_cpp_fun(lb_create_Fun, "lb_create", { 2,2,EXPR_PARA_DYNANIC },PACKET_GLOBAL_FUN);

        register_cpp_fun(lb_indexOf_Fun, "lb_indexOf", { 1,2,EXPR_PARA_DYNANIC });

        register_cpp_fun(lb_lastIndexOf_Fun, "lb_lastIndexOf", { 1,2,EXPR_PARA_DYNANIC });

        register_cpp_fun(lb_mid_Fun, "lb_mid", { EXPR_INT,-1, EXPR_INT_OPTION });

        register_cpp_fun(lb_copy_Fun, "lb_copy", { });

        register_cpp_fun(lb_removeAt_Fun, "lb_removeAt", { EXPR_INT });

        register_cpp_fun(lb_takeAt_Fun, "lb_takeAt", { EXPR_INT });

        register_cpp_fun(lb_takeFirst_Fun, "lb_takeFirst", {  });

        register_cpp_fun(lb_takeLast_Fun, "lb_takeLast", { });

        register_cpp_fun(lb_swapItemsAt_Fun, "lb_swapItemAt", { EXPR_INT,EXPR_INT });

        register_cpp_fun(lb_reserve_Fun, "lb_reserve", { EXPR_INT });

        register_cpp_fun(lb_sort_Fun, "lb_sort", { 0, EXPR_INT_OPTION });

        register_cpp_fun(lb_sortStruct_Fun, "lb_sortStruct", { EXPR_INT, 0, EXPR_INT_OPTION });


    }
}

void initQStringFunTab()
{
    if(!s_qstring_fun_sys_load)
    {
        s_qstring_fun_sys_load = true;

        s_register_call_back_fun = qstring_fun_cpp;
        s_register_pack_id = EXPR_U16STRING;//PString_Struct_Id;

        register_cpp_fun(qstr_fromZfc_Fun, "qstr_fromZfc", {EXPR_STRING},PACKET_GLOBAL_FUN);
        register_cpp_fun(qstring_toZfc_Fun, "qstr_toZfc", {  });
        register_cpp_fun(getCharList_Fun, "qstr_getCharList", {  });
        register_cpp_fun(qstr_at_Fun, "qstr_at", {EXPR_INT});
        register_cpp_fun(qstr_size_Fun, "qstr_size", { });

        s_register_call_back_fun = u16string_fun_cpp;

       register_cpp_fun(qstr_back_Fun,"qstr_back",{});
       register_cpp_fun(qstr_front_Fun, "qstr_front", {});
       register_cpp_fun(qstr_chop_Fun,"qstr_chop",{EXPR_INT});
       register_cpp_fun(qstr_chopped_Fun,"qstr_chopped",{EXPR_INT});
       register_cpp_fun(qstr_clear_Fun,"qstr_clear",{});


       register_cpp_fun(qstr_append_Fun, "qstr_append", { EXPR_U16STRING });
        //第一次加入，后续可以加1个可选的Int参数。参数检查的时候，做特别判断。只能是最后一个参数时可选的，而且只能有1个。
        //倒数第二个值，是默认参数缺省的默认值。
       register_cpp_fun(qstr_compare_Fun, "qstr_compare", { EXPR_U16STRING, 1, EXPR_INT_OPTION});

       register_cpp_fun(qstr_contains_Fun, "qstr_contains", { EXPR_U16STRING, 1, EXPR_INT_OPTION});

       register_cpp_fun(qstr_count_Fun, "qstr_count", { EXPR_U16STRING , 1, EXPR_INT_OPTION});

       register_cpp_fun(qstr_endsWith_Fun, "qstr_endsWith", { EXPR_U16STRING , 1, EXPR_INT_OPTION});

       register_cpp_fun(qstr_startsWith_Fun, "qstr_startsWith", { EXPR_U16STRING , 1, EXPR_INT_OPTION});

       register_cpp_fun(qstr_indexOf_Fun, "qstr_indexOf", {1,3,EXPR_PARA_DYNANIC });

       register_cpp_fun(qstr_lastIndexOf_Fun, "qstr_lastIndexOf", { 1,3,EXPR_PARA_DYNANIC });

       register_cpp_fun(qstr_insert_Fun, "qstr_insert", {EXPR_INT, EXPR_U16STRING });

       register_cpp_fun(qstr_isEmpty_Fun, "qstr_isEmpty", {});

       register_cpp_fun(qstr_isLower_Fun, "qstr_isLower", {});

       register_cpp_fun(qstr_isUpper_Fun, "qstr_isUpper", {});

       register_cpp_fun(qstr_left_Fun, "qstr_left", { EXPR_INT });

       register_cpp_fun(qstr_right_Fun, "qstr_right", { EXPR_INT });

       register_cpp_fun(qstr_leftJustified_Fun, "qstr_leftJustified", { EXPR_INT , EXPR_WCHAR, 0, EXPR_INT_OPTION });

       register_cpp_fun(qstr_rightJustified_Fun, "qstr_rightJustified", { EXPR_INT , EXPR_WCHAR, 0, EXPR_INT_OPTION });


       register_cpp_fun(qstr_mid_Fun, "qstr_mid", { EXPR_INT, -1, EXPR_INT_OPTION });

       register_cpp_fun(qstr_push_back_Fun, "qstr_push_back", { EXPR_U16STRING });

       register_cpp_fun(qstr_push_front_Fun, "qstr_push_front", { EXPR_U16STRING });

       register_cpp_fun(qstr_remove_Fun, "qstr_remove", { EXPR_INT,EXPR_INT });

       //第一次引入动态参数。参数个数是2到4个。
       register_cpp_fun(qstr_replace_Fun, "qstr_replace", { 2,4,EXPR_PARA_DYNANIC });


       register_cpp_fun(qstr_simplified_Fun, "qstr_simplified", {});

       register_cpp_fun(qstr_split_Fun, "qstr_split", { 1,1,EXPR_PARA_DYNANIC});

       register_cpp_fun(qstr_toDouble_Fun, "qstr_toDouble", { });

       register_cpp_fun(qstr_toFloat_Fun, "qstr_toFloat", { });

       register_cpp_fun(qstr_toInt_Fun, "qstr_toInt", { 10, EXPR_INT_OPTION });

       register_cpp_fun(qstr_toLongLong_Fun, "qstr_toLongLong", { 10, EXPR_INT_OPTION });

       register_cpp_fun(qstr_toLower_Fun, "qstr_toLower", { });

       register_cpp_fun(qstr_toUpper_Fun, "qstr_toUpper", { });

       register_cpp_fun(qstr_trimmed_Fun, "qstr_trimmed", { });

       register_cpp_fun(qstr_truncate_Fun, "qstr_truncate", { EXPR_INT });

       register_cpp_fun(qstr_setPosChar_Fun, "qstr_setPosChar", { EXPR_INT,EXPR_WCHAR });

       register_cpp_fun(qstr_number_Fun, "qstr_number", { 1,3, EXPR_PARA_DYNANIC },PACKET_GLOBAL_FUN);

    }
}

//字符的方法
void initCharFunTab()
{
    if(!s_char_fun_sys_load)
    {
        s_char_fun_sys_load = true;

        s_register_call_back_fun = zf_fun_cpp;
        s_register_pack_id = EXPR_CHAR;

        register_cpp_fun(zf_num_Fun, "num", { });

        register_cpp_fun(zf_hex_Fun, "hex", { });


    }
}

void initQCharFunTab()
{
    if (!s_qchar_fun_sys_load)
    {
        s_qchar_fun_sys_load = true;

        s_register_call_back_fun = qchar_fun_cpp;
        s_register_pack_id = EXPR_WCHAR;


        register_cpp_fun(qchar_unicode_Fun, "unicode", { });

        register_cpp_fun(qchar_isDigit_Fun, "isDigit", { });
        register_cpp_fun(qchar_isLetter_Fun, "isLetter", { });
        register_cpp_fun(qchar_isLetterOrNumber_Fun, "isLetterOrNumber", { });
        register_cpp_fun(qchar_isPrint_Fun, "isPrint", { });
        register_cpp_fun(qchar_isLower_Fun, "qchr_isLower", { });
        register_cpp_fun(qchar_isUpper_Fun, "qchr_isUpper", { });
        register_cpp_fun(qchar_number_Fun, "qchr_number", {10,EXPR_INT_OPTION});


    }
}



int qregexp_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    //int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

    //ExprValue* errorPara = nullptr;

    switch (fun_info->fun_id)
    {
        case reg_match_Fun:
        case reg_globalMatch_Fun:
        case reg_setPatternOptions_Fun:
        case ret_setPattern_Fun:
        case reg_captureCount_Fun:
        case reg_re_isValid_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);
            STRUCT_VALUE_DATA* pData = (STRUCT_VALUE_DATA*)obj->value.vpoint;
            QRegularExpression & re = std::any_cast<QRegularExpression&>(pData->pCppObj);

            switch(fun_info->fun_id)
            {
                case reg_match_Fun:
                {
                --lastIndex;
                ExprValue* paraOffset = callFunStack->at(lastIndex);

                --lastIndex;
                ExprValue* paraStr = callFunStack->at(lastIndex);

                //std::cout << "--1" << re.pattern().toStdString() << std::endl;

                QRegularExpressionMatch match = re.match(*(QString*)paraStr->value.vpoint, paraOffset->value.vint);

                exprRet->type = EXPR_STRUCT;

                STRUCT_VALUE_DATA* pRet =  new STRUCT_VALUE_DATA();
    #ifdef PIN_MEM_REF
                newTime();
    #endif
                pRet->pCppObj = match;
                pRet->structType = "RegMatch";
                pRet->structTypeId = REGMATCH_Struct_ID;

                exprRet->value.vpoint = pRet;
                }
                break;

                case reg_globalMatch_Fun:
                {
                    --lastIndex;
                    ExprValue* paraOffset = callFunStack->at(lastIndex);

                    --lastIndex;
                    ExprValue* paraStr = callFunStack->at(lastIndex);

                    //std::cout << "--1" << re.pattern().toStdString() << std::endl;

                    QRegularExpressionMatchIterator match = re.globalMatch(*(QString*)paraStr->value.vpoint, paraOffset->value.vint);

                    exprRet->type = EXPR_STRUCT;

                    STRUCT_VALUE_DATA* pRet = new STRUCT_VALUE_DATA();
#ifdef PIN_MEM_REF
                    newTime();
#endif
                    pRet->pCppObj = match;
                    pRet->structType = "RegMatchIter";
                    pRet->structTypeId = REGMATCH_ITER_Struct_ID;

                    exprRet->value.vpoint = pRet;
                }
                break;

                case reg_captureCount_Fun:
                {
                    exprRet->type = EXPR_INT;
                    exprRet->value.vint = re.captureCount();
                }
                break;

                case reg_re_isValid_Fun:
                {
                    exprRet->type = EXPR_BOOL;
                    exprRet->value.vbool = re.isValid();
                }
                break;


                case reg_errorString_Fun:
                {
                    exprRet->type = EXPR_STRING;
                    exprRet->setString(re.errorString().toStdString());
                }
                break;

                case reg_setPatternOptions_Fun:
                {
                    isNeedRetValue = false;

                    --lastIndex;
                    ExprValue* paraMode = callFunStack->at(lastIndex);

                    re.setPatternOptions((QRegularExpression::PatternOptions)paraMode->value.vint);
                    //pData->pCppObj = re;

                }
                break;



                case ret_setPattern_Fun:
                {
                    isNeedRetValue = false;

                    --lastIndex;
                    ExprValue* paraPattern = callFunStack->at(lastIndex);

                    if(paraPattern->type == EXPR_STRING)
                    {
                        re.setPattern(QString(*(QByteArray*)paraPattern->value.vpoint));
                    }
                    else if(paraPattern->type == EXPR_U16STRING)
                    {
                        re.setPattern(QString(*(QString*)paraPattern->value.vpoint));
                    }
                    else
                    {
                        QString err = QString(u8"错误：行号 %1 语句 %2 函数setPattern 参数需要字符串类型").arg(curLine).arg(curStatement);
                        AbortException(err);
                    }
                    //pData->pCppObj = re;
                }
                break;
            }

        }
        break;

        case reg_captured_Fun:
        case reg_capturedStart_Fun:
        case reg_capturedEnd_Fun:
        case reg_capturedLength_Fun:
        case reg_hasMatch_Fun:
        case reg_lastCapturedIndex_Fun:
        case reg_capturedTexts_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);

            STRUCT_VALUE_DATA* pData = (STRUCT_VALUE_DATA*)obj->value.vpoint;
            QRegularExpressionMatch& match = std::any_cast<QRegularExpressionMatch&>(pData->pCppObj);

            switch(fun_info->fun_id)
            {

                case reg_captured_Fun:
                {

                --lastIndex;
                ExprValue* paraNth = callFunStack->at(lastIndex);


                exprRet->type = EXPR_U16STRING;

                exprRet->value.vpoint = new QString(match.captured(paraNth->value.vint));
    #ifdef PIN_MEM_REF
                newTime();
    #endif
                }
                break;

                case reg_capturedStart_Fun:
                case reg_capturedEnd_Fun:
                case reg_capturedLength_Fun:
                {

                    --lastIndex;
                    ExprValue* paraNth = callFunStack->at(lastIndex);

                    exprRet->type = EXPR_INT;

                    if (fun_info->fun_id == reg_capturedStart_Fun)
                    {
                        exprRet->value.vint = match.capturedStart(paraNth->value.vint);
                    }
                    else if (fun_info->fun_id == reg_capturedEnd_Fun)
                    {
                        exprRet->value.vint = match.capturedEnd(paraNth->value.vint);
                    }
                    else if (fun_info->fun_id == reg_capturedLength_Fun)
                    {
                        exprRet->value.vint = match.capturedLength(paraNth->value.vint);
                    }
                }
                break;

                case reg_hasMatch_Fun:
                {
                    exprRet->type =  EXPR_BOOL;
                    exprRet->value.vbool = match.hasMatch();
                }
                    break;

                case reg_lastCapturedIndex_Fun:
                {
                    exprRet->type = EXPR_INT;
                    exprRet->value.vint = match.lastCapturedIndex();
                }
                break;

                case reg_isValid_Fun:
                {
                    exprRet->type = EXPR_BOOL;
                    exprRet->value.vbool = match.isValid();
                }
                break;

                case reg_capturedTexts_Fun:
                {
                    exprRet->type = EXPR_LIST;

                    QStringList retList = match.capturedTexts();
                    std::vector<ExprValue*>* pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>(retList.size());
#ifdef PIN_MEM_REF
                    newTime();
#endif
                    exprRet->value.vpoint = pData;
                    addListMapRefNum(pData);

                    for (int i = 0, c = retList.size(); i < c; ++i)
                    {
                        ExprValue* pExpr = new ExprValue();
                        pExpr->type = EXPR_U16STRING;
                        pExpr->value.vpoint = new QString(std::move(retList[i]));

                        pData->operator[](i) = pExpr;
#ifdef PIN_MEM_REF
                        newTime(2);
#endif
                    }
                }
                break;

            }

        }
            break;

        case reg_hasNext_Fun:
        case reg_next_Fun:
        case reg_peekNext_Fun:
        {
            ExprValue* obj = callFunStack->at(lastIndex);

            STRUCT_VALUE_DATA* pData = (STRUCT_VALUE_DATA*)obj->value.vpoint;
            QRegularExpressionMatchIterator& match = std::any_cast<QRegularExpressionMatchIterator&>(pData->pCppObj);

            switch (fun_info->fun_id)
            {

                case reg_hasNext_Fun:
                {
                    exprRet->type = EXPR_BOOL;
                    exprRet->value.vbool = match.hasNext();
                }
                break;

                case reg_next_Fun:
                case reg_peekNext_Fun:
                {
                    exprRet->type = EXPR_STRUCT;
                    STRUCT_VALUE_DATA* pRet = new  STRUCT_VALUE_DATA();
#ifdef PIN_MEM_REF
                    newTime();
#endif
                    if (fun_info->fun_id == reg_next_Fun)
                    {
                        pRet->pCppObj = match.next();
                    }
                    else
                    {
                        pRet->pCppObj = match.peekNext();
                    }

                    pRet->structType = "RegMatch";
                    pRet->structTypeId = REGMATCH_Struct_ID;
                    exprRet->value.vpoint = pRet;
                }
                break;

            }


        }
        break;
    }

    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }
    return 0;
}

void initRegExpFunTab()
{
    if (!s_regexp_sys_load)
    {
        s_regexp_sys_load = true;

        s_register_call_back_fun = qregexp_fun_cpp;
        s_register_pack_id = REGEXP_Struct_ID; //使用reg做关键字


        register_cpp_fun(reg_match_Fun, "match", {EXPR_U16STRING, 0, EXPR_INT_OPTION});
        register_cpp_fun(reg_globalMatch_Fun, "globalMatch", { EXPR_U16STRING, 0, EXPR_INT_OPTION });

        register_cpp_fun(reg_captureCount_Fun, "captureCount", {});
        register_cpp_fun(reg_errorString_Fun, "errorString", {});


        register_cpp_fun(reg_setPatternOptions_Fun, "setPatternOptions", {EXPR_INT});
        register_cpp_fun(ret_setPattern_Fun, "setPattern", {1,1,EXPR_PARA_DYNANIC});
        register_cpp_fun(reg_re_isValid_Fun, "reg_isValid", {1,1,EXPR_PARA_DYNANIC});


        s_register_pack_id = REGMATCH_Struct_ID; //使用mat做关键字

        register_cpp_fun(reg_captured_Fun, "captured", {0, EXPR_INT_OPTION});

        register_cpp_fun(reg_capturedStart_Fun, "capturedStart", { 0, EXPR_INT_OPTION });

        register_cpp_fun(reg_capturedEnd_Fun, "capturedEnd", { 0, EXPR_INT_OPTION });

        register_cpp_fun(reg_capturedLength_Fun, "capturedLength", { 0, EXPR_INT_OPTION });

        register_cpp_fun(reg_hasMatch_Fun, "hasMatch", {});

        register_cpp_fun(reg_isValid_Fun, "mat_isValid", {});

        register_cpp_fun(reg_capturedTexts_Fun, "capturedTexts", {});

        register_cpp_fun(reg_lastCapturedIndex_Fun, "lastCapturedIndex", {});



        s_register_pack_id = REGMATCH_ITER_Struct_ID;

        register_cpp_fun(reg_hasNext_Fun, "hasNext", {}); 
        register_cpp_fun(reg_next_Fun, "next", {});
        register_cpp_fun(reg_peekNext_Fun, "peekNext", {});
    }
}

#ifdef NDD_PIN_FUN
void initNddFunTab()
{
    if (!s_ndd_fun_sys_load)
    {
        s_ndd_fun_sys_load = true;

        s_register_call_back_fun = ndd_fun_cpp;
        s_register_pack_id = EXPR_NDD;

        register_cpp_fun(ndd_getMainWin_Fun, "getMainWin", {},PACKET_GLOBAL_FUN);

        s_register_pack_id = NddMainWin_Struct_ID;

        //新建一个编辑框
        register_cpp_fun(ndd_newEditor_Fun, "newEditor", {},PACKET_GLOBAL_FUN);

        //获取当前编辑框
        register_cpp_fun(ndd_getCurEdit_Fun, "getCurEdit", {});

        //获取当前编辑框打开的文件路径。
        register_cpp_fun(ndd_curEditFilePath_Fun, "curEditFilePath", {});


        //按编号获取编辑框
        register_cpp_fun(ndd_getEdit_Fun, "getEdit", {EXPR_INT});

        s_register_pack_id = Editor_Struct_ID;





        //获取编辑框文本内容
        register_cpp_fun(ndd_getText_Fun, "getText", {});

        //设置编辑框文本内容
        register_cpp_fun(ndd_setText_Fun, "setText", { EXPR_STRING});

        //获取pos开始，len长的字符串。
        register_cpp_fun(ndd_getTextRange_Fun, "getTextRange", {EXPR_INT,EXPR_INT });


        //设置编辑框某一行的文本内容
        register_cpp_fun(ndd_getLine_Fun, "getLine", { EXPR_INT });

        register_cpp_fun(ndd_lineCount_Fun, "lineCount", {  });

        register_cpp_fun(ndd_setsel_Fun, "setSel", { EXPR_INT,EXPR_INT });

        register_cpp_fun(ndd_gotoPos_Fun, "gotoPos", { EXPR_INT });

        register_cpp_fun(ndd_gotoLine_Fun, "gotoLine", { EXPR_INT });

        register_cpp_fun(ndd_setcurpos_Fun, "setCurPos", { EXPR_INT });

        register_cpp_fun(ndd_posBefore_Fun, "posBefore", { EXPR_INT });

        register_cpp_fun(ndd_posAfter_Fun, "posAfter", { EXPR_INT });


        register_cpp_fun(ndd_setanchor_Fun, "setAnchor", { EXPR_INT });

        register_cpp_fun(ndd_getcurpos_Fun, "getCurPos", {  });

        register_cpp_fun(ndd_getanchor_Fun, "getAnchor", { });

        register_cpp_fun(ndd_selectall_Fun, "selectAll", {  });

        register_cpp_fun(ndd_getselstart_Fun, "getSelStart", {  });

        register_cpp_fun(ndd_getselend_Fun, "getSelEnd", {  });

        register_cpp_fun(ndd_setselstart_Fun, "setSelStart", { EXPR_INT });

        register_cpp_fun(ndd_setselend_Fun, "setSelEnd", { EXPR_INT });

        register_cpp_fun(ndd_setemptysel_Fun, "setEmptySel", { EXPR_INT });

        register_cpp_fun(ndd_lineFromPos_Fun, "lineFromPos", { EXPR_INT });

        register_cpp_fun(ndd_posFromLine_Fun, "posFromLine", { EXPR_INT });

        register_cpp_fun(ndd_getLineEndPos_Fun, "getLineEndPos", { EXPR_INT });

        register_cpp_fun(ndd_lineLength_Fun, "lineLength", { EXPR_INT });

        register_cpp_fun(ndd_getSelText_Fun, "getSelText", { });

        register_cpp_fun(ndd_removeSelText_Fun, "removeSelText", { });

        register_cpp_fun(ndd_replaceSelText_Fun, "replaceSelText", { EXPR_STRING });

        register_cpp_fun(ndd_insertAtPos_Fun, "insertAtPos", { EXPR_INT, EXPR_STRING });

        register_cpp_fun(ndd_deleteRange_Fun, "deleteRange", { EXPR_INT,EXPR_INT });

        register_cpp_fun(ndd_highLight_Fun, "highLight", { EXPR_INT,EXPR_INT,EXPR_INT });

        register_cpp_fun(ndd_clear_highLight_Fun, "clearHighLight", { EXPR_INT,EXPR_INT,EXPR_INT });

        register_cpp_fun(ndd_clearAllHighLight_Fun, "clearAllHighLight", {  });

        register_cpp_fun(ndd_beginundo_Fun, "beginUndo", {  });

        register_cpp_fun(ndd_endundo_Fun, "endUndo", {  });

    }
}
#endif

void initExcelFunTab()
{
    if (!s_excel_fun_sys_load)
    {
        s_excel_fun_sys_load = true;

        s_register_call_back_fun = excelInfo_fun_cpp;
        s_register_pack_id = EXPR_EXCEL;

        //0或1个参数。
        register_cpp_fun(excel_create_Fun, "el_create", { 0,1,EXPR_PARA_DYNANIC });

        register_cpp_fun(excel_open_Fun, "el_open", { 0,1,EXPR_PARA_DYNANIC });

        register_cpp_fun(excel_save_Fun, "save", {  });

        register_cpp_fun(excel_saveAs_Fun, "saveAs", { EXPR_STRING });

        register_cpp_fun(excel_isOpen_Fun, "isOpen", {  });

        register_cpp_fun(excel_close_Fun, "el_close", {  });

        register_cpp_fun(excel_addWorksheet_Fun, "addSheet", { EXPR_STRING });

        register_cpp_fun(excel_deleteWorksheet_Fun, "deleteSheet", { EXPR_STRING });


        register_cpp_fun(excel_listSheetNames_Fun, "listSheetNames", { });

        register_cpp_fun(excel_sheetExists_Fun, "sheetExists", { EXPR_STRING});

        register_cpp_fun(excel_cloneSheet_Fun, "cloneSheet", { EXPR_STRING,EXPR_STRING});

        register_cpp_fun(excel_sheetCount_Fun, "sheetCount", {});




        //发现macos下面不支持worksheet(index)下标方式，总是保存。干脆只支持string名称拉倒
        //register_cpp_fun(excel_worksheet_Fun, "worksheet", { 1,1,EXPR_PARA_DYNANIC}, excelInfo_fun_cpp);

        register_cpp_fun(excel_worksheet_Fun, "worksheet", { EXPR_STRING});


        s_register_pack_id = XLWorksheet_Struct_ID;

        register_cpp_fun(XLWorksheet_setCell_Fun, "setCell", { 2,3,EXPR_PARA_DYNANIC });

        register_cpp_fun(XLWorksheet_setFormula_Fun, "setFormula", { 2,3,EXPR_PARA_DYNANIC });

        //设置公式

        register_cpp_fun(XLWorksheet_cell_Fun, "cell", { 1,2,EXPR_PARA_DYNANIC });

        register_cpp_fun(XLWorksheet_formula_Fun, "formula", { 1,2,EXPR_PARA_DYNANIC });

        register_cpp_fun(XLWorksheet_rowCount_Fun, "rowCount", {  });

        register_cpp_fun(XLWorksheet_columnCount_Fun, "columnCount", {  });

        register_cpp_fun(XLWorksheet_setName_Fun, "setName", { EXPR_STRING });

        register_cpp_fun(XLWorksheet_name_Fun, "name", {  });

        register_cpp_fun(XLWorksheet_deleteRow_Fun, "deleteRow", { EXPR_INT });

        //register_cpp_fun(pin_desc_Fun, "xws_desc", { }, pin_fun_cpp, EXPR_EXCEL);


    }
}

void initFileFunTab()
{
    if (!s_file_fun_sys_load)
    {
        s_file_fun_sys_load = true;

        s_register_call_back_fun = qfileInfo_fun_cpp;
        s_register_pack_id = EXPR_FILE;

        register_cpp_fun(birthTime_Fun,"birthTime",{});

        register_cpp_fun(lastModified_Fun,"lastModified",{});

        register_cpp_fun(lastRead_Fun,"lastRead",{});

        register_cpp_fun(metadataChangeTime_Fun,"metadataChangeTime",{});

        register_cpp_fun(absoluteFilePath_Fun,"absoluteFilePath",{});


        register_cpp_fun(absolutePath_Fun,"absolutePath",{});


        register_cpp_fun(baseName_Fun,"baseName",{});


        register_cpp_fun(canonicalFilePath_Fun,"canonicalFilePath",{});


        register_cpp_fun(canonicalPath_Fun,"canonicalPath",{});


        register_cpp_fun(completeBaseName_Fun,"completeBaseName",{});


        register_cpp_fun(completeSuffix_Fun,"completeSuffix",{});


        register_cpp_fun(fileName_Fun,"fileName",{});


        register_cpp_fun(filePath_Fun,"filePath",{});


        register_cpp_fun(owner_Fun,"owner",{});


        register_cpp_fun(path_Fun,"path",{});


        register_cpp_fun(suffix_Fun,"suffix",{});


        register_cpp_fun(symLinkTarget_Fun,"symLinkTarget",{});

        s_register_call_back_fun = qfile_fun_cpp;
        s_register_pack_id = EXPR_FILE;
        //QFile
        register_cpp_fun(exists_Fun,"wj_exists",{});

        register_cpp_fun(isFile_Fun, "isFile", {});

        register_cpp_fun(isDir_Fun,"isDir",{});

        register_cpp_fun(isExecutable_Fun,"isExecutable",{});

        register_cpp_fun(isHidden_Fun,"isHidden",{});

        register_cpp_fun(isReadable_Fun,"isReadable",{});

        register_cpp_fun(isRelative_Fun,"isRelative",{});


        register_cpp_fun(isShortcut_Fun,"isShortcut",{});


        register_cpp_fun(isSymLink_Fun,"isSymLink",{});


        register_cpp_fun(isSymbolicLink_Fun,"isSymbolicLink",{});


        register_cpp_fun(isWritable_Fun,"isWritable",{});


        register_cpp_fun(moveToTrash_Fun,"moveToTrash",{});


        register_cpp_fun(remove_Fun,"wj_remove",{});


        register_cpp_fun(copy_Fun,"wj_copy",{EXPR_STRING});


        register_cpp_fun(rename_Fun, "rename", {EXPR_STRING});



        register_cpp_fun(wj_open_Fun, "wj_open", { EXPR_STRING });


        register_cpp_fun(size_Fun, "wj_size", {});


        register_cpp_fun(close_Fun, "wj_close", {});


        register_cpp_fun(readAll_Fun, "readAll", {});


        register_cpp_fun(read_Fun, "read", {EXPR_INT64});

        register_cpp_fun(read_line_Fun, "readLine", {0, EXPR_INT_OPTION });


        register_cpp_fun(write_Fun, "write", { EXPR_STRING,-1, EXPR_INT_OPTION });


        //register_cpp_fun(writeMax_Fun, "writeMax", { EXPR_STRING, EXPR_INT64 }, qfile_fun_cpp,EXPR_FILE);


        register_cpp_fun(seek_Fun, "seek", {EXPR_INT64 });


        register_cpp_fun(pos_Fun, "pos", {});

        //1到3个参数。
        register_cpp_fun(childFiles_Fun, "childFiles", { 1,3,EXPR_PARA_DYNANIC },PACKET_GLOBAL_FUN);

        //register_cpp_fun(pin_desc_Fun, "wj_desc", {}, pin_fun_cpp, EXPR_FILE);

        //当前目录的path
        register_cpp_fun(currentPath_Fun, "wj::currentPath", { },PACKET_GLOBAL_FUN);

        //路径是否存在，全局文件方法
        register_cpp_fun(pathExist_Fun, "wj::pathExist", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(fileExist_Fun, "wj::exists", { EXPR_STRING },PACKET_GLOBAL_FUN);//对文件和文件夹都有效果。

        register_cpp_fun(static_moveToTrash_Fun, "wj::moveToTrash", { EXPR_STRING },PACKET_GLOBAL_FUN);//对文件和文件夹都有效果。

        //删除文件。凡是全局函数，均使用::来区分。而_前缀，只是区分类名。
        register_cpp_fun(rmfile_Fun, "wj::remove", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(wj_static_copy_Fun, "wj::copy", { EXPR_STRING,EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(static_rename_Fun, "wj::rename", { EXPR_STRING,EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(static_symLinkTarget_Fun, "wj::symLinkTarget", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(static_pathJoin_Fun, "wj::pathJoin", { EXPR_STRING,EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(static_getRegularFilePath_Fun, "wj::getRegularFilePath", { EXPR_STRING },PACKET_GLOBAL_FUN);




        register_cpp_fun(homePath_Fun, "wj::homePath", { },PACKET_GLOBAL_FUN);

        register_cpp_fun(drives_Fun, "wj::drives", { },PACKET_GLOBAL_FUN);

        register_cpp_fun(tempPath_Fun, "wj::tempPath", { },PACKET_GLOBAL_FUN);

        register_cpp_fun(isAbsolutePath_Fun, "wj::isAbsolutePath", {EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(isRelativePath_Fun, "wj::isRelativePath", { EXPR_STRING },PACKET_GLOBAL_FUN);


        register_cpp_fun(setCurrent_Fun, "wj::setCurrent", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(toNativeSeparators_Fun, "wj::toNativeSeparators", { EXPR_STRING },PACKET_GLOBAL_FUN);


        register_cpp_fun(dirRename_Fun, "wj::dirRename", { EXPR_STRING,EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(rmdir_Fun, "rmdir", { EXPR_STRING });

        register_cpp_fun(rmpath_Fun, "rmpath", { EXPR_STRING });

        register_cpp_fun(mkdir_Fun, "mkdir", { EXPR_STRING });

        register_cpp_fun(mkpath_Fun, "mkpath", { EXPR_STRING });

        register_cpp_fun(static_rmdir_Fun, "wj::rmdir", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(static_rmpath_Fun, "wj::rmpath", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(static_mkdir_Fun, "wj::mkdir", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(static_mkpath_Fun, "wj::mkpath", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(static_cd_Fun, "wj::cd", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(static_cdUp_Fun, "wj::cdUp", { },PACKET_GLOBAL_FUN);

        register_cpp_fun(static_open_Fun, "wj::open", {EXPR_STRING,EXPR_STRING},PACKET_GLOBAL_FUN);




    }
}

void initMapFunTab()
{
    if (!s_map_fun_sys_load)
    {
        s_map_fun_sys_load = true;

        s_register_call_back_fun = map_fun_cpp;
        s_register_pack_id = EXPR_MAP;

        register_cpp_fun(zd_clear_Fun, "zd_clear", {});

        register_cpp_fun(zd_size_Fun, "zd_size", {});

        register_cpp_fun(zd_isEmpty_Fun, "zd_isEmpty", {});


        register_cpp_fun(zd_contains_Fun, "zd_contains", {1,1,EXPR_PARA_DYNANIC });

        register_cpp_fun(zd_remove_Fun, "zd_remove", { 1,1,EXPR_PARA_DYNANIC });

        register_cpp_fun(zd_keys_Fun, "zd_keys", {  });

        register_cpp_fun(zd_value_Fun, "zd_value", { 1,1,EXPR_PARA_DYNANIC });

        register_cpp_fun(zd_copy_Fun, "zd_copy", {});

    }
}


QStringList getParaFromCmdStr(QByteArray& srcText, PinParser::RealCallFunContext* ctx)
{

    QString cmdStr = QString(srcText);

    //先看看是否有转义字符存在。有则先去翻译转义。

    //是否存在\' 或 \" 保护起来的部分
    QByteArray checkEscape1("\'");
    QByteArray checkEscape2("\"");

    int times1 = srcText.count(checkEscape1);
    int times2 = srcText.count(checkEscape2);

    if (times1 > 0 && (times1 % 2) != 0)
    {
        if (ctx)
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2 命令行 %3 格式错误，使用 ' 转义部分未能配对，是否漏写 ' ?").arg(curLine).arg(curStatement).arg(cmdStr);
            AbortException(msg);
        }
        else
        {
            QString msg = QString(u8"错误：命令行 %1 格式错误，使用 ' 转义部分未能配对，是否漏写 ' ?").arg(cmdStr);

            std::cout << msg.toStdString();

            return QStringList();
        }
    }

    if (times2 > 0 && (times2 % 2) != 0)
    {
        if (ctx)
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2 命令行 %3 格式错误，使用 \" 转义部分未能配对，是否漏写 \" ? ").arg(curLine).arg(curStatement).arg(cmdStr);
            AbortException(msg);
        }
        else
        {
            QString msg = QString(u8"错误：命令行 %3 格式错误，使用 \" 转义部分未能配对，是否漏写 \" ? ").arg(cmdStr);

            std::cout << msg.toStdString();

            return QStringList();
        }
    }

    QStringList argList;

    //把' " 部分做一个整体处理，不进行分割
    if (times1 > 0 || times2 > 0)
    {
        QStringList tempStr;

        //再把"" 或 '' 的部分分割出来，作为一个整体。
        QString pattern(R"((['"])(.*?)\1)");
        QRegularExpression regex(pattern);

        int lastPos = 0;

        QRegularExpressionMatchIterator i = regex.globalMatch(cmdStr);
        while (i.hasNext()) {
            QRegularExpressionMatch match = i.next();

            // 获取完整匹配内容，即带引号的部分
            QString fullMatch = match.captured(0);

            // 获取匹配结果在输入字符串中的起始位置

            int position = match.capturedStart();

            //把不是“” 括起来的部分，找出来，加入到tempStr
            tempStr.append(cmdStr.mid(lastPos, position - lastPos));

            // 获取匹配结果的长度
            lastPos = position + match.capturedLength();

            //再把“括起来的部分，加入到tempStr
            tempStr.append(fullMatch);
        }

        //最后尾部可能留一截没有匹配的。
        if (lastPos < cmdStr.size())
        {
            tempStr.append(cmdStr.mid(lastPos));
        }

        for (int i = 0, s = tempStr.size(); i < s; ++i)
        {
            //是整体，不需要拆分
            if (tempStr.at(i).startsWith('"') || tempStr.at(i).startsWith('\''))
            {
                argList.append(tempStr.at(i).mid(1, tempStr.at(i).size() - 2));
            }
            else
            {
                //使用空格拆分
                argList.append(tempStr.at(i).split(' '));
            }
        }
    }
    else
    {
        //没有需要“” '' 处理的情况。
        argList = cmdStr.split(' ');
    }

    //去掉全空白
    for (int i = argList.size() - 1; i >= 0; --i)
    {
        if (argList.at(i).trimmed().size() == 0)
        {
            argList.removeAt(i);
        }
    }

    return argList;
}


//执行全局pin方法。
int pin_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    //int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

    //int curParaIndex = 0;

    switch (fun_info->fun_id)
    {
        case pin_exec_Fun:
        case pin_exec_output_Fun:
        {

           exprRet->type = EXPR_INT;
           exprRet->value.vint = 0;


            //是全局方法。
            ExprValue* obj = callFunStack->at(lastIndex);
            if (obj->type == EXPR_GLOBAL_PACKNAME)
            {
                --lastIndex;
                ExprValue* paraCmd = callFunStack->at(lastIndex);

                //字符串获取的时候，已经在表达式求值中，被处理过转义字符了。
                 //下面只需要处理 ' 或 “ 即可。
                QByteArray srcText = *((QByteArray*)(paraCmd->value.vpoint));
                QByteArrayList cmdList;



                //检查是否带有管道，此时会有多个命令，分别执行。
                if (srcText.contains('|'))
                {
                    //带有管道，会比较麻烦。需要依次执行。
                    cmdList = srcText.split('|');
                    for (int i = cmdList.size()-1; i >=0; --i)
                    {
                        //依次执行每条命令
                        QByteArray cmd = cmdList.at(i).trimmed();
                        if (cmd.isEmpty())
                        {
                            //把空命令给删除掉。
                            cmdList.removeAt(i);
                        }
                    }
                }
                else
                {
                    cmdList << srcText;
                }

                bool hasMorePipeCmd = false; //后续是否还有管道命令接着执行
                QByteArray lastOutput;

                //开始依次执行命令。
                while (!cmdList.isEmpty())
                {
                    srcText = cmdList.takeFirst();

                    //是否还有管道命令
                    hasMorePipeCmd = !cmdList.isEmpty();

                    QStringList argList = getParaFromCmdStr(srcText, ctx);

                    if (argList.size() >= 1)
                    {
                        QStringList argv;

                        if (argList.size() > 1)
                        {
                            argv = argList.mid(1);
                        }

                        QProcess process;

                        process.start(argList.at(0), argv);

                        if (!process.waitForStarted()) {   // 等待进程启动
                            QString msg = QString(u8"警告：行号 %1 语句 %2 执行命令 %3 启动失败！").arg(curLine).arg(curStatement).arg(QString(srcText));
                            std::cout << msg.toStdString() << std::endl;

                            exprRet->value.vint = 1;

                        }
                        // 将前一个进程的输出写入第二个进程的输入。这里必须要放在waitForStarted的后面，否则执行失败。
                        if (!lastOutput.isEmpty())
                        {
                            process.write(lastOutput);
                            process.closeWriteChannel();
                        }

                        if (!process.waitForFinished(5000))
                        {  // 等待进程完成。这里最多5秒，5s没有完成，也会超时。
                            //避免卡死，继续等待几次。一共30s。

                            int times = 5;

                            while (!shouldExit && times > 0 && !process.waitForFinished(5000))
                            {
                                --times;
                                QCoreApplication::processEvents();

                                if (shouldExit)
                                {
                                    break;
                                }
                            }

                            //如果最后还是超时，则退出,说明还是没有完成。
                            if (QProcess::Timedout == process.error())
                            {

                                QString msg = QString(u8"警告：行号 %1 语句 %2 执行命令 %3 失败！").arg(curLine).arg(curStatement).arg(QString(srcText));
                                std::cout << msg.toStdString() << std::endl;

                                exprRet->value.vint = 2;
                            }
                            else
                            {
                                exprRet->value.vint = process.exitCode();
                            }

                        }
                        else
                        {
                            exprRet->value.vint = process.exitCode();
                        }

                        //现在是否能返回呢,如果没有管道命令后，可以返回。
                        if (!hasMorePipeCmd || exprRet->value.vint != QProcess::NormalExit)
                        {

                            //这个方法会返回2个值，目前唯一个需要返回2个值的方法。
                            //第一个返回值是输出，第二个返回值是返回码。
                            if (fun_info->fun_id == pin_exec_output_Fun)
                            {
                                //函数的返回值使用栈返回
                                ExprValue* exprRet0 = new ExprValue();

#ifdef PIN_MEM_REF
                                newTime();
#endif

                                exprRet0->type = EXPR_STRING;

                                QByteArray output = process.readAllStandardOutput();


                                //如果有错误，而且输出是空，则接受错误
                                if (output.isEmpty() && exprRet->value.vint != QProcess::NormalExit)
                                {
                                    output = process.readAllStandardError();
                                    exprRet0->value.vpoint = new QByteArray(std::move(output));
#ifdef PIN_MEM_REF
                                    newTime();
#endif
                                }
                                else
                                {
                                    exprRet0->value.vpoint = new QByteArray(std::move(output));
#ifdef PIN_MEM_REF
                                    newTime();
#endif
                                }

                                //先返回输出。
                                callFunStack->push_back(exprRet0);

                            }
                            //必须跳出。因为可能是发生错误了。
                            if (exprRet->value.vint != QProcess::NormalExit)
                            {
                                break;
                            }

                        }
                        else
                        {
                            //不能返回，后续还有管道。上一条命令已经完成，而且成功执行。
                             // 获取前面一个进程的输出
                            lastOutput = process.readAllStandardOutput();
                        }
                    }
                }
            }
        }
        break;

        case pin_desc_Fun:
        {
            //返回对象的信息
            exprRet->type = EXPR_MAP;

            std::unordered_map<ExprValue, ExprValue*>* pMap = new std::unordered_map<ExprValue, ExprValue*>();
#ifdef PIN_MEM_REF
            newTime();
#endif
            addListMapRefNum(pMap);
            exprRet->value.vpoint = pMap;

            //取对象
            ExprValue* obj = callFunStack->at(lastIndex);


            switch (obj->type)
            {
            case EXPR_FUN:
            {
                FUN_SYM_INFO* pFunSym = nullptr;

                //如果是回调函数，要给出真实调用名称。
                SymNode* pHdFun = getVarFromSymTable(*obj->varName, ctx);
                if (pHdFun->type == EXPR_CALL_BACK_FUN)
                {
                    //如果是回调函数
                    ExprValue key;
                    key.setString("call_hs");

                    ExprValue value;
                    value.setString(*((std::string*)(pHdFun->value.vpoint)));

                    //这里key没有释放，但是加入到pMap，等于是浅拷贝转移。
                    //value 一样，直接调用shallowMoveCopy前拷贝转移。
                    pMap->insert({ key,value.shallowMoveCopy() });

                    pFunSym = findFunBlock(*((std::string*)(pHdFun->value.vpoint)));
                }
                else
                {
                    //加入函数的参数，和返回类型
                    pFunSym = findFunBlock(*obj->varName);
                }

                if (pFunSym != nullptr)
                {

                    //加入参数列表。
                    {
                        std::vector<std::string>* pParaList = pFunSym->paraList;

                        ExprValue key;
                        key.setString("paraList");

                        ExprValue value;
                        value.type = EXPR_LIST;

                        std::vector<ExprValue*>* pData = nullptr;

                        if (pParaList != nullptr)
                        {
                            int paraNums = pParaList->size() / 2; //前面是名称，后面是类型
                            pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>(paraNums);
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            for (int i = 0; i < paraNums; ++i)
                            {
                                ExprValue expr;
                                expr.setString(pParaList->at(paraNums + i));

                                pData->operator[](i) = expr.shallowMoveCopy();
                            }
                        }
                        else
                        {
                            pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>();
#ifdef PIN_MEM_REF
                            newTime();
#endif
                        }


                        value.value.vpoint = pData;

                        addListMapRefNum(pData);

                        //这里key没有释放，但是加入到pMap，等于是浅拷贝转移。
                        //value 一样，直接调用shallowMoveCopy前拷贝转移。
                        pMap->insert({ key,value.shallowMoveCopy() });
                    }

                    //加入返回值
                    {
                        std::vector<std::string>* pRetList = pFunSym->retList;

                        ExprValue key;
                        key.setString("retList");

                        ExprValue value;
                        value.type = EXPR_LIST;

                        std::vector<ExprValue*>* pData = nullptr;

                        if (pRetList != nullptr)
                        {
                            int paraNums = pRetList->size();
                            pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>(paraNums);
#ifdef PIN_MEM_REF
                            newTime();
#endif
                            for (int i = 0; i < paraNums; ++i)
                            {
                                ExprValue expr;
                                expr.setString(pRetList->at(i));

                                pData->operator[](i) = expr.shallowMoveCopy();
                            }
                        }
                        else
                        {
                            pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>();
#ifdef PIN_MEM_REF
                            newTime();
#endif
                        }


                        value.value.vpoint = pData;

                        addListMapRefNum(pData);

                        //这里key没有释放，但是加入到pMap，等于是浅拷贝转移。
                        //value 一样，直接调用shallowMoveCopy前拷贝转移。
                        pMap->insert({ key,value.shallowMoveCopy() });
                    }
                }
            }
                break;

            case EXPR_FILE:
            {
                {
                    ExprValue key;
                    key.setString("filePath");

                    ExprValue value;
                    value.setString(obj->getFilePath());

                    //这里key没有释放，但是加入到pMap，等于是浅拷贝转移。
                    //value 一样，直接调用shallowMoveCopy前拷贝转移。
                    pMap->insert({ key,value.shallowMoveCopy() });
                }
            }
                break;
                //结构体
            case EXPR_STRUCT:
            {
                //结构体类型名称
                //加入类型。
                {
                    ExprValue key;
                    key.setString("structName");

                    ExprValue value;
                    value.setString(obj->getStructName());

                    //这里key没有释放，但是加入到pMap，等于是浅拷贝转移。
                    //value 一样，直接调用shallowMoveCopy前拷贝转移。
                    pMap->insert({ key,value.shallowMoveCopy() });
                }
            }
            break;

            //结构体类型申明。
            case EXPR_STRUCT_DEC:
            {
                //前面是变量，后面是类型
                std::vector<std::string>* pParalist = (std::vector<std::string>*)obj->value.vpoint;

                int paraNum = pParalist->size()/2;

                //加入结构体申明
                ExprValue key;
                key.setString("desc");

                ExprValue value;
                value.type = EXPR_MAP;

                std::unordered_map<ExprValue, ExprValue*>* pNewMap = new std::unordered_map<ExprValue, ExprValue*>();
#ifdef PIN_MEM_REF
                newTime();
#endif
                addListMapRefNum(pNewMap);
                value.value.vpoint = pNewMap;

                if (paraNum > 0)
                {
                    for (int i=0, s= paraNum; i<s; ++i)
                    {
                        ExprValue name;
                        name.setString(pParalist->at(i));

                        ExprValue type;
                        type.setString(pParalist->at(i + paraNum));

                        pNewMap->insert({name, type.shallowMoveCopy()});
                    }
                }


                //这里key没有释放，但是加入到pMap，等于是浅拷贝转移。
                //value 一样，直接调用shallowMoveCopy前拷贝转移。
                pMap->insert({ key,value.shallowMoveCopy() });
            }
            break;

            }

            //加入类型。
            {
                ExprValue key;
                key.setString("type");

                ExprValue value;
                value.setString(getTypeDescName(obj->type,obj));

                //这里key没有释放，但是加入到pMap，等于是浅拷贝转移。
                //value 一样，直接调用shallowMoveCopy前拷贝转移。
                pMap->insert({ key,value.shallowMoveCopy() });
            }

            //加入名称
            if(obj->varName != nullptr)
            {
                ExprValue key;
                key.setString("name");

                ExprValue value;
                value.setString(*(obj->varName));

                //这里key没有释放，但是加入到pMap，等于是浅拷贝转移。
                //value 一样，直接调用shallowMoveCopy前拷贝转移。
                pMap->insert({ key,value.shallowMoveCopy() });
            }
        }
        break;

        case pin_line_Fun:
        {
            exprRet->type = EXPR_INT ;
            exprRet->value.vint = curLine;
        }
        break;

        case pin_fun_Fun:
        {
            exprRet->type = EXPR_STRING;
            exprRet->setString(getCurFunName());
        }
        break;

        case pin_yield_Fun:
        {
            isNeedRetValue = false;
            QCoreApplication::processEvents();
        }
        break;

        case pin_exit_Fun:
        {
            isNeedRetValue = false;

            --lastIndex;
            ExprValue* expr = callFunStack->at(lastIndex);

            s_exit_code = expr->value.vint;

            QString msg = QString(u8"退出程序：行号 %1 语句 %2 执行exit 退出语句").arg(curLine).arg(curStatement);
            AbortException(msg);  
    }
        break;

        case pin_getopt_Fun:
        {
            --lastIndex;
            ExprValue* paraLong = callFunStack->at(lastIndex);

            QMap<QByteArray,bool> longList;
            std::vector<ExprValue*>* plongList = (std::vector<ExprValue*>*)paraLong->value.vpoint;

            //把参数按照格式化，输出一个map方式
            if (plongList != nullptr && plongList->size() > 0)
            {
                for (int i = 0, s = plongList->size(); i < s; ++i)
                {
                    QByteArray* pBytes = (QByteArray*)plongList->at(i)->value.vpoint;
                    if (pBytes->endsWith('='))
                    {
                        longList.insert("--" + pBytes->mid(0, pBytes->length() - 1), true);
                    }
                    else
                    {
                        longList.insert("--" + *pBytes, false);
                    }
                }
            }

            --lastIndex;
            ExprValue* paraShort = callFunStack->at(lastIndex);

            //把参数按照格式化，输出一个map方式
            if (paraShort->value.vpoint != nullptr)
            {
                QByteArray bytes = QByteArray(*(QByteArray*)paraShort->value.vpoint);

                bytes = bytes.simplified();
                bytes.replace(' ', "");

                for (int i = 0, s = bytes.size()-1; i < s; ++i)
                {
                    char c = bytes.at(i);
                    if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == ':')
                    {
                        //是不需要参数的flag
                        if (c != ':' && bytes.at(i+1) != ':')
                        {
                            QByteArray key("-");
                            key.append(c);

                            longList.insert(key, false);
                        }
                        else if (c != ':' && bytes.at(i + 1) == ':')
                        {
                            QByteArray key("-");
                            key.append(c);

                            longList.insert(key, true);
                        }
                        else if (c == ':')
                        {
                            continue;
                        }
                    }
                }
                //最后一个
                char c = bytes.back();
                if (c != ':' && ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
                {
                    QByteArray key("-");
                    key.append(c);

                    longList.insert(key, false);
                }
            }

            --lastIndex;
            ExprValue* paraList = callFunStack->at(lastIndex);

            std::vector<ExprValue*>* pList = (std::vector<ExprValue*>*)paraList->value.vpoint;

            std::unordered_map<ExprValue, ExprValue*>* pRetMap = new std::unordered_map<ExprValue, ExprValue*>();
#ifdef PIN_MEM_REF
            newTime();
#endif

            //把参数按照格式化，输出一个map方式
            if (pList != nullptr && pList->size() > 0)
            {
                bool isNeedInLongList = true;//是否需要在参数列表中。第1个肯定是需要的。

                for (int i = 0, s = pList->size(); i < s; ++i)
                {
                    QByteArray curBytes = QByteArray(*(QByteArray*)pList->at(i)->value.vpoint);

                    //如果是最后1个参数,而且是无参，则需要加入
                    if (i == s - 1)
                    {
                        //是合法参数，而且是无参参数
                        if (longList.contains(curBytes))
                        {
                            if (!longList.value(curBytes))//无参参数，合法
                            {
                                ExprValue key;
                                key.setStringBytes(curBytes);

                                //给空字符串的参数值。
                                ExprValue value;
                                value.setString("");

                                //判断是否存在
                                auto it = pRetMap->find(key);
                                if (it != pRetMap->end())
                                {
                                    //告警，参数重复给定
                                    it->second->setString("");
                                    key.freeMem();
                                    value.freeMem();

                                    QString err = QString(u8"警告：行号%1 语句 %2 字段 %3 多次给定，请检查！")
                                        .arg(curLine).arg(curStatement).arg(QString(curBytes));
                                    std::cout << err.toStdString() << std::endl;
                                }
                                else
                                {
                                    pRetMap->insert({ key, value.shallowMoveCopy() });
                                }
                            }
                            else
                            {
                                //非法，有参参数，但是后面没有了，说明漏了参数
                                QString err = QString(u8"错误：行号%1 语句 %2 字段 %3 需要参数，命令行输入遗漏 %3 参数值，请检查！")
                                    .arg(curLine).arg(curStatement).arg(QString(curBytes));
                                AbortException(err);
                            }
                        }
                        else
                        {
                            //无效参数，参数不存在。
                            //需要参数存在，但是参数确不存在，则错误。
                             //错误，该参数需要参数，没有给。
                            QString err = QString(u8"错误：行号%1 语句 %2 字段 %3 不是合法参数，命令行输入错误，请检查！")
                                .arg(curLine).arg(curStatement).arg(QString(curBytes));
                            AbortException(err);
                        }
                    }
                    else
                    {
                        QByteArray nextBytes = QByteArray(*(QByteArray*)pList->at(i + 1)->value.vpoint);

                        //需要在参数列表，而且真在，则合适。
                        if (isNeedInLongList)
                        {
                            //参数存在。
                            if (longList.contains(curBytes))
                            {
                                //是有参参数，需要参数。
                                if (longList.value(curBytes))
                                {
                                    if (nextBytes.startsWith("-"))
                                    {
                                        //错误，该参数需要参数，没有给。
                                        QString err = QString(u8"错误：行号%1 语句 %2 字段 %3 需要参数，命令行输入遗漏 %3 的参数值，请检查！")
                                            .arg(curLine).arg(curStatement).arg(QString(curBytes));
                                        AbortException(err);
                                    }
                                    else
                                    {
                                        ExprValue key;
                                        key.setStringBytes(curBytes);

                                        ExprValue value;
                                        value.setStringBytes(nextBytes);

                                        //判断是否存在
                                        auto it = pRetMap->find(key);
                                        if (it != pRetMap->end())
                                        {
                                            //告警，参数重复给定
                                            it->second->setStringBytes(nextBytes);
                                            key.freeMem();
                                            value.freeMem();

                                            QString err = QString(u8"警告：行号%1 语句 %2 字段 %3 多次给定，请检查！")
                                                .arg(curLine).arg(curStatement).arg(QString(curBytes));
                                            std::cout << err.toStdString() << std::endl;;
                                        }
                                        else
                                        {
                                            pRetMap->insert({ key, value.shallowMoveCopy() });
                                        }

                                        //跳过下一个参数
                                        ++i;

                                        //继续需要参数
                                        isNeedInLongList = true;
                                    }
                                }
                                else
                                {
                                    //是无参参数,不能给参数
                                    if (!nextBytes.startsWith("-"))
                                    {
                                        //错误，该参数不需要参数，确给。
                                        QString err = QString(u8"错误：行号%1 语句 %2 字段 %3 不需要参数值，命令行输入却给参数值，请检查！")
                                            .arg(curLine).arg(curStatement).arg(QString(curBytes));
                                        AbortException(err);
                                    }
                                    else
                                    {
                                        ExprValue key;
                                        key.setStringBytes(curBytes);

                                        //给空字符串的参数值。
                                        ExprValue value;
                                        value.setString("");

                                        //判断是否存在
                                        auto it = pRetMap->find(key);
                                        if (it != pRetMap->end())
                                        {
                                            //告警，参数重复给定
                                            it->second->setString("");
                                            key.freeMem();
                                            value.freeMem();

                                            QString err = QString(u8"警告：行号%1 语句 %2 字段 %3 多次给定，请检查！")
                                                .arg(curLine).arg(curStatement).arg(QString(curBytes));
                                            std::cout << err.toStdString() << std::endl;;
                                        }
                                        else
                                        {

                                            pRetMap->insert({ key, value.shallowMoveCopy() });
                                        }

                                        //这里不需要跳过下一个参数，因为前一个参数是无参参数，下面继续。

                                        //继续需要参数
                                        isNeedInLongList = true;
                                    }
                                }
                            }
                            else
                            {
                                //需要参数存在，但是参数确不存在，则错误。
                                 //错误，该参数需要参数，没有给。
                                QString err = QString(u8"错误：行号%1 语句 %2 字段 %3 不是合法参数，命令行输入错误，请检查！")
                                    .arg(curLine).arg(curStatement).arg(QString(curBytes));
                                AbortException(err);
                            }
                        }
                        else
                        {
                            //这里好像不用做什么，上面已经全部做完了。
                        }
                    }

                }
            }

            exprRet->type = EXPR_MAP;
            exprRet->value.vpoint = pRetMap;
            addListMapRefNum(pRetMap);
        }
        break;
    }

    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }

    return 0;
}

int string_fun_cpp(CPP_FUN_INFO* fun_info, PinParser::RealCallFunContext* ctx)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    int lastIndex = callFunStack->size() - 1;
    int hasError = 0;

    //取出函数对象,在倒数第二个。
    --lastIndex;

    //函数的返回值使用栈返回
    ExprValue* exprRet = new ExprValue();
    bool isNeedRetValue = true;
#ifdef PIN_MEM_REF
    newTime();
#endif

    //int curParaIndex = 0;

    ExprValue* obj = callFunStack->at(lastIndex);
    QByteArray* pBytes =  (QByteArray*)obj->value.vpoint;

    /*
    if(pBytes == nullptr)
    {
        pBytes = new QByteArray();
#ifdef PIN_MEM_REF
        newTime();
#endif
        obj->value.vpoint = pBytes;
    }*/

    switch (fun_info->fun_id)
    {

        //静态函数。
    case zfc_create_Fun:
    {
        ExprValue* obj = callFunStack->at(lastIndex);
        if (obj->type == EXPR_GLOBAL_PACKNAME)
        {
            if (obj->value.vpacktype == EXPR_STRING)
            {
                --lastIndex;
                ExprValue* paraCh = callFunStack->at(lastIndex);

                --lastIndex;
                ExprValue* paraSize = callFunStack->at(lastIndex);

                exprRet->type = EXPR_STRING;
                exprRet->value.vpoint = new QByteArray(paraSize->value.vint, paraCh->value.vchar);
#ifdef PIN_MEM_REF
                newTime();
#endif

            }
            else
            {
                hasError = 2;
            }
        }
    }
    break;
    case zfc_number_Fun:
    {
        ExprValue* obj = callFunStack->at(lastIndex);
        if (obj->type == EXPR_GLOBAL_PACKNAME)
        {
            if (obj->value.vpacktype == EXPR_STRING)
            {
                //先取出参数个数。
                int callParaNum = lastIndex;

                //1个参数
                if (1 == callParaNum)
                {
                    --lastIndex;
                    ExprValue* para1 = callFunStack->at(lastIndex);

                    if (para1->type == EXPR_INT || para1->type == EXPR_INT64)
                    {
                        exprRet->type = EXPR_STRING;
                        QByteArray* pRet = new QByteArray();
                        pRet->setNum(para1->value.vint64);
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pRet;

                    }
                    else if (para1->type == EXPR_FLOAT)
                    {
                        exprRet->type = EXPR_STRING;
                        QByteArray* pRet = new QByteArray();
                        pRet->setNum(para1->value.vfloat);
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pRet;

                    }
                }
                else if (2 == callParaNum)
                {
                    --lastIndex;
                    ExprValue* para2 = callFunStack->at(lastIndex);

                    --lastIndex;
                    ExprValue* para1 = callFunStack->at(lastIndex);

                    if ((para1->type == EXPR_INT || para1->type == EXPR_INT64) && para2->type == EXPR_INT)
                    {
                        exprRet->type = EXPR_STRING;
                        QByteArray* pRet = new QByteArray();
                        pRet->setNum(para1->value.vint64, para2->value.vint);
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pRet;

                    }
                    else if ((para1->type == EXPR_FLOAT) && para2->type == EXPR_CHAR)
                    {
                        exprRet->type = EXPR_STRING;
                        QByteArray* pRet = new QByteArray();
                        pRet->setNum(para1->value.vfloat, para2->value.vchar);
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pRet;

                    }
                }
                else if (3 == callParaNum)
                {
                    --lastIndex;
                    ExprValue* para3 = callFunStack->at(lastIndex);

                    --lastIndex;
                    ExprValue* para2 = callFunStack->at(lastIndex);

                    --lastIndex;
                    ExprValue* para1 = callFunStack->at(lastIndex);

                    if ((para1->type == EXPR_FLOAT) && para2->type == EXPR_CHAR && para3->type == EXPR_INT)
                    {
                        exprRet->type = EXPR_STRING;
                        QByteArray* pRet = new QByteArray();
                        pRet->setNum(para1->value.vfloat, para2->value.vchar, para3->value.vint);
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        exprRet->value.vpoint = pRet;

                    }
                }
                else
                {
                    QString msg = QString(u8"错误：行号 %1 语句 %2 参数格式错误。setNum 函数有5种形式，均无法匹配！").arg(curLine).arg(curStatement);
                    AbortException(msg);
                }
            }
            else
            {
                hasError = 2;
            }
        }
    }
    break;

    case zfc_fromBase64_Fun:
    case checksum_Fun:
    case compress_Fun:
    case uncompress_Fun:
    case zfc_fromDoubleHex_Fun:
    case zfc_fromIntHex_Fun:
    case static_zfc_reverse_Fun:
    {

        ExprValue* obj = callFunStack->at(lastIndex);
        if (obj->type == EXPR_GLOBAL_PACKNAME)
        {
            if (obj->value.vpacktype == EXPR_STRING)
            {
                switch(fun_info->fun_id)
                {
                    case zfc_fromBase64_Fun:
                    {
                        --lastIndex;
                        ExprValue* para2 = callFunStack->at(lastIndex);

                        --lastIndex;
                        ExprValue* para1 = callFunStack->at(lastIndex);


                        exprRet->type = EXPR_STRING;
                        QByteArray ret = QByteArray::fromBase64(*(QByteArray*)para1->value.vpoint, (QByteArray::Base64Options)para2->value.vint);

                        exprRet->value.vpoint = new QByteArray(std::move(ret));
    #ifdef PIN_MEM_REF
                        newTime();
    #endif

                    }
                    break;

                    case checksum_Fun:
                    {
                        --lastIndex;
                        ExprValue* para2 = callFunStack->at(lastIndex);

                        --lastIndex;
                        ExprValue* para1 = callFunStack->at(lastIndex);


                        exprRet->type = EXPR_INT;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
                        quint16 ret = qChecksum(*(QByteArray*)para1->value.vpoint, (Qt::ChecksumType)para2->value.vint);
#else
                        QByteArray* pBytes = (QByteArray*)(para1->value.vpoint);

                        quint16 ret = qChecksum(pBytes->data(), pBytes->size(), (Qt::ChecksumType)para2->value.vint);
#endif
                        exprRet->value.vint = ret;
                    }
                    break;

                    case compress_Fun:
                    {
                        --lastIndex;
                        ExprValue* para2 = callFunStack->at(lastIndex);

                        --lastIndex;
                        ExprValue* para1 = callFunStack->at(lastIndex);

                        exprRet->type = EXPR_STRING;

                        if (para2->value.vint < 0 || para2->value.vint > 9)
                        {
                            para2->value.vint = -1;
                        }
                        QByteArray ret = qCompress(*(QByteArray*)para1->value.vpoint, para2->value.vint);
                        exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
                        newTime();
#endif
                    }
                    break;

                    case uncompress_Fun:
                    {
                        --lastIndex;
                        ExprValue* para1 = callFunStack->at(lastIndex);


                        exprRet->type = EXPR_STRING;
                        QByteArray ret = qUncompress(*(QByteArray*)para1->value.vpoint);
                        exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
                        newTime();
#endif
                    }
                    break;


                    //从double 8字节的Hex，读取后得到数字，在把数字转字符串。
                    //从int64 8 字节的hen，读取得到qint64数组，把数字转字符串。
                    case zfc_fromDoubleHex_Fun:
                    case zfc_fromIntHex_Fun:
                    {
                        --lastIndex;
                        ExprValue* paraBigOrLittle = callFunStack->at(lastIndex);

                        --lastIndex;
                        ExprValue* paraHexStr = callFunStack->at(lastIndex);
                        exprRet->type = EXPR_STRING;

                        QByteArray ret = pBytes->fromHex(*(QByteArray*)paraHexStr->value.vpoint);

                        //默认是小端。即字符串前面的低字节字符串，放入double的低位置空间。

                        //0 小端，1 大端。
                        if (paraBigOrLittle->value.vint == 1)
                        {
                            std::reverse(ret.begin(), ret.end());
                        }

                        if (ret.size() <= 8)
                        {
                            if (fun_info->fun_id == zfc_fromDoubleHex_Fun)
                            {
                                double value = 0.0f;
                                memcpy(&value, ret.data(), ret.size());

                                ret.setNum(value, 'f');
                            }
                            else
                            {
                                qlonglong value = 0;
                                memcpy(&value, ret.data(), ret.size());
                                ret.setNum(value);
                            }
                        }
                        else
                        {
                            QString msg = QString(u8"错误：行 %1 语句 %2 字符串越界，参数字符串最长为16个字节，当前参数字符串有 %3 字节！。").arg(curLine).arg(curStatement).arg(ret.size());
                            AbortException(msg);
                        }

                        exprRet->setStringBytes(ret);
                    }
                    break;

                    case static_zfc_reverse_Fun:
                    {
                        --lastIndex;
                        ExprValue* paraStr = callFunStack->at(lastIndex);
                        QByteArray pRet(QByteArray(*(QByteArray*)paraStr->value.vpoint));
#ifdef PIN_MEM_REF
                        newTime();
#endif
                        std::reverse(pRet.begin(), pRet.end());
                        exprRet->setStringBytes(pRet);

                    }
                    break;

                }
            }
            else
            {
                hasError = 2;
            }
        }
    }
    break;


    case zfc_append_Fun:
    case zfc_contains_Fun:
    case zfc_count_Fun:
    case endsWith_Fun:
    case startsWith_Fun:
    case zfc_push_back_Fun:
    case zfc_push_front_Fun:
    case zfc_fromHex_Fun:


        //追加字符串
        {


            --lastIndex;
            ExprValue* para = callFunStack->at(lastIndex);
            if(para->type == EXPR_STRING && para->value.vpoint != nullptr)
            {
                switch (fun_info->fun_id)
                {
                case zfc_append_Fun:
                    {
                        isNeedRetValue = false;

                        pBytes->append(*(QByteArray*)para->value.vpoint);
                    }
                    break;
                case zfc_contains_Fun:
                    {
                        exprRet->type = EXPR_BOOL;
                        exprRet->value.vbool = pBytes->contains(*(QByteArray*)para->value.vpoint);
                    }
                    break;
                case zfc_count_Fun:
                    {
                        exprRet->type = EXPR_INT;
                        exprRet->value.vint = pBytes->count(*(QByteArray*)para->value.vpoint);
                    }
                    break;
                case endsWith_Fun:
                {
                    exprRet->type = EXPR_BOOL;
                    exprRet->value.vbool = pBytes->endsWith(*(QByteArray*)para->value.vpoint);
                }
                    break; 

                case startsWith_Fun:
                {
                    exprRet->type = EXPR_BOOL;
                    exprRet->value.vbool = pBytes->startsWith(*(QByteArray*)para->value.vpoint);
                }

                break;

                case zfc_push_back_Fun:
                {
                    isNeedRetValue = false;
                    pBytes->push_back(*(QByteArray*)para->value.vpoint);
                }
                    break;

                case zfc_push_front_Fun:
                {
                    isNeedRetValue = false;
                    pBytes->push_front(*(QByteArray*)para->value.vpoint);
                }
                break;

                case zfc_fromHex_Fun:
                {
                    exprRet->type = EXPR_STRING;
                    QByteArray ret = pBytes->fromHex(*(QByteArray*)para->value.vpoint);

                    exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
                    newTime();
#endif
                }
                break;


                }
            }
            else if (para->type == EXPR_CHAR)
            {
                switch (fun_info->fun_id)
                {
                case zfc_append_Fun:
                {
                    isNeedRetValue = false;

                    pBytes->append(para->value.vchar);
                }
                break;
                case zfc_contains_Fun:
                {
                    exprRet->type = EXPR_BOOL;
                    exprRet->value.vbool = pBytes->contains(para->value.vchar);
                }
                break;
                case zfc_count_Fun:
                {
                    exprRet->type = EXPR_INT;
                    exprRet->value.vint = pBytes->count(para->value.vchar);
                }
                break;
                case endsWith_Fun:
                {
                    exprRet->type = EXPR_BOOL;
                    exprRet->value.vbool = pBytes->endsWith(para->value.vchar);
                }
                break;

                case startsWith_Fun:
                {
                    exprRet->type = EXPR_BOOL;
                    exprRet->value.vbool = pBytes->startsWith(para->value.vchar);
                }
                break;

                case zfc_push_back_Fun:
                {
                    isNeedRetValue = false;
                    pBytes->push_back(para->value.vchar);
                }
                break;

                case zfc_push_front_Fun:
                {
                    isNeedRetValue = false;
                    pBytes->push_front(para->value.vchar);
                }
                break;


                }
            }
        }
        break;

    case zfc_at_Fun:
    case chop_Fun:
    case chopped_Fun:
    case zfc_left_Fun:
    case zfc_right_Fun:
    case zfc_transCode_Fun:

    {

        //访问字符串中某一个字符
        --lastIndex; //第一个参数
        ExprValue* para = callFunStack->at(lastIndex);
        if(para->type == EXPR_INT || para->type == EXPR_INT64)
        {
            switch(fun_info->fun_id)
            {
            case zfc_at_Fun:
            {
                exprRet->type = EXPR_CHAR;

                if (para->value.vint <= pBytes->size() - 1)
                {
                    exprRet->value.vchar = pBytes->at(para->value.vint);
                }
                else
                {
                    exprRet->value.vchar = '\0';

                    QString msg = QString(u8"错误：行 %1 语句 %2 at 获取位置字符失败，位置值 %3 超过当前字符串长度 %4 (下标从0开始计算)！").arg(curLine).arg(curStatement).arg(para->value.vint).arg(pBytes->size());
                    //std::cout << msg.toStdString() << std::endl;
                    AbortException(msg);
                }   
            }
            break;

            case chop_Fun:
            {
                isNeedRetValue = false;
                pBytes->chop(para->value.vint64);
            }
            break;

            case chopped_Fun:
            {
                exprRet->type = EXPR_STRING;

                if(para->value.vint64 > (pBytes->size()) || para->value.vint64 < 0)
                {
                    QString msg = QString(u8"错误：行 %1 语句 %2 chopped 尾巴字符失败，长度值 %3 超过当前字符串长度 %4 (下标从0开始计算)！").arg(curLine).arg(curStatement).arg(para->value.vint64).arg(pBytes->size());
                    AbortException(msg);
                }
                QByteArray ret = pBytes->chopped(para->value.vint64);
                exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
                newTime();
#endif
            }
            break;

            case zfc_left_Fun:
            {
                exprRet->type = EXPR_STRING;
                QByteArray ret = pBytes->left(para->value.vint);
                exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
                newTime();
#endif
            }
            break; 
            case zfc_right_Fun:
            {
                exprRet->type = EXPR_STRING;
                QByteArray ret = pBytes->right(para->value.vint);
                exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
                newTime();
#endif
            }
            break;



            case zfc_transCode_Fun:
            {
                --lastIndex; //第1个参数
                ExprValue* paraSrcCode = callFunStack->at(lastIndex);

                exprRet->type = EXPR_STRING;

                QString textOut;
                bool ret = tranStrToUNICODE((CODE_ID)paraSrcCode->value.vint,pBytes->data(),pBytes->size(),textOut);

                if(!ret)
                {
                    QString msg = QString(u8"警告：行号 %1 语句 %2 字符串编码转换中有编码 %3 未能识别的字符，转换结果错误。请检查给定原始编码是否正确！").arg(curLine).arg(curStatement)
                        .arg(QString(getQtCodecNameById(para->value.vint)));
                    std::cerr << msg.toStdString() << std::endl;
                }

                QTextCodec* pTranCode = getTextCodeByCode((CODE_ID)para->value.vint);
                QByteArray byteRet = pTranCode->fromUnicode(textOut);

                exprRet->value.vpoint = new QByteArray(std::move(byteRet));
#ifdef PIN_MEM_REF
                newTime();
#endif
            }
                break;
            }
        }
        else
        {
            hasError = 1;
        }
    }
        break;

    case leftJustified_Fun:
    case rightJustified_Fun:
    {
        //访问字符串中某一个字符
        --lastIndex; //倒数第一个参数

        ExprValue* paraTrun = callFunStack->at(lastIndex);

        --lastIndex; //倒数第2个参数

        ExprValue* paraFill = callFunStack->at(lastIndex);

        --lastIndex; //倒数第3个参数
        ExprValue* paraWidth = callFunStack->at(lastIndex);

        exprRet->type = EXPR_STRING;

        QByteArray ret;
        if (fun_info->fun_id == leftJustified_Fun)
        {
            ret = pBytes->leftJustified(paraWidth->value.vint, paraFill->value.vchar, (paraTrun->value.vint != 0));
        }
        else
        {
            ret = pBytes->rightJustified(paraWidth->value.vint, paraFill->value.vchar, (paraTrun->value.vint != 0));
        }
        exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;

    //重载变参类型，要检查参数具体形式。
    case zfc_replace_Fun:
    {
        //先取出参数个数。
        int callParaNum = lastIndex;
        isNeedRetValue = false;
        //2个参数
        if (2 == callParaNum)
        {
            --lastIndex;
            ExprValue* para2 = callFunStack->at(lastIndex);

            --lastIndex;
            ExprValue* para1 = callFunStack->at(lastIndex);

            if (para1->type == EXPR_STRING && para2->type == EXPR_STRING)
            {
                //匹配 QByteArray&replace(const QByteArray& before, const QByteArray& after)

                pBytes->replace(*(QByteArray*)para1->value.vpoint, *(QByteArray*)para2->value.vpoint);
            }
            //匹配 QByteArray&replace(char before, char after)
            else if (para1->type == EXPR_CHAR && para2->type == EXPR_CHAR)
            {
                pBytes->replace(para1->value.vchar, para2->value.vchar);
            }
            else if (para1->type == EXPR_CHAR && para2->type == EXPR_STRING)
            {
            //匹配QByteArray&replace(char before, const QByteArray& after)
            pBytes->replace(para1->value.vchar, *(QByteArray*)para2->value.vpoint);
            }
        }
        else if (3 == callParaNum)
        {
        --lastIndex;
        ExprValue* para3 = callFunStack->at(lastIndex);

        --lastIndex;
        ExprValue* para2 = callFunStack->at(lastIndex);

        --lastIndex;
        ExprValue* para1 = callFunStack->at(lastIndex);

        //匹配QByteArray& replace(int pos, int len, const QByteArray& after)

        if ((para1->type == EXPR_INT || para1->type == EXPR_INT64) && (para2->type == EXPR_INT || para2->type == EXPR_INT64) && para3->type == EXPR_STRING)
        {
            pBytes->replace(para1->value.vint, para2->value.vint, *(QByteArray*)para3->value.vpoint);
        }
        }
        else if (4 == callParaNum)
        {
        //匹配QByteArray &QByteArray::replace(int pos, int len, const char *after, int alen);

        --lastIndex;
        ExprValue* para4 = callFunStack->at(lastIndex);

        --lastIndex;
        ExprValue* para3 = callFunStack->at(lastIndex);

        --lastIndex;
        ExprValue* para2 = callFunStack->at(lastIndex);

        --lastIndex;
        ExprValue* para1 = callFunStack->at(lastIndex);

        if ((para1->type == EXPR_INT || para1->type == EXPR_INT64) && (para2->type == EXPR_INT || para2->type == EXPR_INT64) && para3->type == EXPR_STRING && (para4->type == EXPR_INT || para4->type == EXPR_INT64))
        {
            const char* after = ((QByteArray*)para3->value.vpoint)->constData();

            pBytes->replace(para1->value.vint, para2->value.vint, after, para4->value.vint);
        }
        }
        else
        {
        QString msg = QString(u8"错误：行号 %1 语句 %2 参数格式错误。replace 函数有5种形式，均无法匹配！").arg(curLine).arg(curStatement);
        AbortException(msg);
        }
    }
    break;

    case toHex_Fun:
    {
        //先取出参数个数。
        int callParaNum = lastIndex;
        //0个参数
        if (0 == callParaNum)
        {
            exprRet->type = EXPR_STRING;
            QByteArray ret = pBytes->toHex();
            exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
            newTime();
#endif
        }
        else if (1 == callParaNum)
        {
            --lastIndex;
            ExprValue* para1 = callFunStack->at(lastIndex);

            if (para1->type == EXPR_CHAR)
            {
                exprRet->type = EXPR_STRING;
                QByteArray ret = pBytes->toHex(para1->value.vchar);
                exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
                newTime();
#endif
            }
            else
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 参数格式错误。toHex 参数只能是空或字符，不能是其它类型！").arg(curLine).arg(curStatement);
                AbortException(msg);
            }
        }
        else
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2 参数格式错误。toHex 函数有2种形式，均无法匹配！").arg(curLine).arg(curStatement);
            AbortException(msg);
        }

    }
    break;

    case zfc_remove_Fun:
    {
        isNeedRetValue = false;

        //访问字符串中某一个字符
        --lastIndex; //倒数第一个参数

        ExprValue* paraLen = callFunStack->at(lastIndex);

        --lastIndex; //倒数第2个参数

        ExprValue* paraPos = callFunStack->at(lastIndex);

        pBytes->remove(paraPos->value.vint, paraLen->value.vint);

    }
    break;

    case zfc_mid_Fun:
    {
        //访问字符串中某一个字符
        --lastIndex; //倒数第一个参数
        ExprValue* paraLen = callFunStack->at(lastIndex);

        --lastIndex; //倒数第2个参数
        ExprValue* paraPos = callFunStack->at(lastIndex);

        exprRet->type = EXPR_STRING;
        QByteArray ret = pBytes->mid(paraPos->value.vint, paraLen->value.vint);

        exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;

    case toBase64_Fun:
    {
        //访问字符串中某一个字符
        --lastIndex; //倒数第一个参数
        ExprValue* para1 = callFunStack->at(lastIndex);
        exprRet->type = EXPR_STRING;

        if (para1->value.vint > 4)
        {
            para1->value.vint = 0;
            QString msg = QString(u8"警告：行 %1 语句 %2 toBase64 参数合法值是0 1 2 4，其余异常值默认做0处理！").arg(curLine).arg(curStatement);
            std::cout << msg.toStdString() << std::endl;
        }

        QByteArray ret = pBytes->toBase64((QByteArray::Base64Options)para1->value.vint);

        exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;

    case zfc_back_Fun:
    {
        exprRet->type = EXPR_CHAR;
        exprRet->value.vchar = pBytes->back();

    }
    break;

    //反转字符串本身
    case zfc_reverse_Fun:
    {
        isNeedRetValue = false;
        std::reverse(pBytes->begin(), pBytes->end());
    }
    break;

    case toDouble_Fun:
    {
        exprRet->type = EXPR_FLOAT;
        bool ok = true;
        exprRet->value.vfloat = pBytes->toDouble(&ok);

        if (!ok)
        {
            QString msg = QString(u8"警告：行 %1 语句 %2 toDouble 转换失败").arg(curLine).arg(curStatement);
            std::cout << msg.toStdString() << std::endl;
        }
    }
    break;

    case toFloat_Fun:
    {
        exprRet->type = EXPR_FLOAT;
        bool ok = true;
        exprRet->value.vfloat = pBytes->toFloat(&ok);

        if (!ok)
        {
            QString msg = QString(u8"警告：行 %1 语句 %2 toFloat 转换失败").arg(curLine).arg(curStatement);
            std::cout << msg.toStdString() << std::endl;
        }
    }
    break; 

    case toInt_Fun :
    {
        --lastIndex; //倒数第一个参数
        ExprValue* para1 = callFunStack->at(lastIndex);

        exprRet->type = EXPR_INT;
        bool ok = true;

        if (para1->type == EXPR_INT)
        {
            exprRet->value.vint = pBytes->toInt(&ok,para1->value.vint);

            if (!ok)
            {
                QString msg = QString(u8"警告：行 %1 语句 %2 toInt 转换失败").arg(curLine).arg(curStatement);
                std::cout << msg.toStdString() << std::endl;
            }
        }
    }
    break;

    case toLongLong_Fun:
    {
        --lastIndex; //倒数第一个参数
        ExprValue* para1 = callFunStack->at(lastIndex);

        exprRet->type = EXPR_INT64;
        bool ok = true;

        if (para1->type == EXPR_INT)
        {
            exprRet->value.vint64 = pBytes->toLongLong(&ok, para1->value.vint);

            if (!ok)
            {
                QString msg = QString(u8"警告：行 %1 语句 %2 toLongLong 转换失败").arg(curLine).arg(curStatement);
                std::cout << msg.toStdString() << std::endl;
            }
        }
    }
    break;

    case toLower_Fun:
    {
        exprRet->type = EXPR_STRING;
        QByteArray ret = pBytes->toLower();

        exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;


    case toUpper_Fun:
    {
        exprRet->type = EXPR_STRING;
        QByteArray ret = pBytes->toUpper();

        exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;


    case trimmed_Fun:
    {
        exprRet->type = EXPR_STRING;
        QByteArray ret = pBytes->trimmed();

        exprRet->value.vpoint = new QByteArray(std::move(ret));
#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;

    case truncate_Fun:
    {
        isNeedRetValue = false;

        --lastIndex; //倒数第一个参数
        ExprValue* para1 = callFunStack->at(lastIndex);
        pBytes->truncate(para1->value.vint); 
    }
    break;

    case setPosChar_Fun:
    {
        isNeedRetValue = false;

        --lastIndex; //倒数第一个参数
        ExprValue* paraChar = callFunStack->at(lastIndex);

        --lastIndex; //倒数第一个参数
        ExprValue* paraPos = callFunStack->at(lastIndex);

        if (paraPos->value.vint <= pBytes->size()-1)
        {
            pBytes->operator[](paraPos->value.vint) = paraChar->value.vchar;
        }
        else
        {
            QString msg = QString(u8"警告：行 %1 语句 %2 setPosChar 设置失败，pos位置值 %3 超过当前字符串长度 %4 (下标从0开始计算)！").arg(curLine).arg(curStatement).arg(paraPos->value.vint).arg(pBytes->size());
            std::cout << msg.toStdString() << std::endl;
        }
    }
    break;


    case zfc_front_Fun:
    {
        exprRet->type = EXPR_CHAR;
        exprRet->value.vchar = pBytes->front();

    }
    break;

    case zfc_isEmpty_Fun:
    {
        exprRet->type = EXPR_BOOL;
        exprRet->value.vbool = pBytes->isEmpty();

    }
    break;

    case simplified_Fun:
    {
        exprRet->type = EXPR_STRING;
        QByteArray ret = pBytes->simplified();
        exprRet->value.vpoint = new QByteArray(std::move(ret));

#ifdef PIN_MEM_REF
        newTime();
#endif
    }
    break;

    //字符串分割
    case zfc_split_Fun:
    {
        exprRet->type = EXPR_LIST;
        --lastIndex; //倒数第一个参数
        ExprValue* para = callFunStack->at(lastIndex);

        QList<QByteArray> pList;

        if(para->type == EXPR_CHAR)
        {
            pList = pBytes->split(para->value.vchar);
        }
        else if(para->type == EXPR_STRING)
        {
            QString str(*pBytes);

            QString splitStr(*((QByteArray*)para->value.vpoint));

            if(!splitStr.isEmpty())
            {
                QStringList result = str.split(splitStr);

                for(int i=0,s=result.size(); i<s; ++i)
                {
                    pList.append(result.at(i).toUtf8());
                }
            }
            else
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 split 的分割字符串参数是空字符串，请检查！").arg(curLine).arg(curStatement);
                AbortException(msg);
            }

        }
        else
        {
            QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 split 的参数只能字符或字符串，请检查！").arg(curLine).arg(curStatement);
            AbortException(msg);
        }
        std::vector<ExprValue*>* pData = (std::vector<ExprValue*>*) new std::vector<ExprValue*>(pList.size());
#ifdef PIN_MEM_REF
        newTime();
#endif
        exprRet->value.vpoint = pData;

        for (int i = 0, c = pList.size(); i < c; ++i)
        {
            ExprValue* pExpr = new ExprValue();
            pExpr->type = EXPR_STRING;
            pExpr->value.vpoint = new QByteArray(std::move(pList[i]));

            pData->operator[](i) = pExpr;
#ifdef PIN_MEM_REF
            newTime(2);
#endif
        }

        //之前说过，凡是返回列表或字典，第一个先不加引用。
        //为什么呢，因为外面把列表expr给变量的时候，都是使用转移方式，而且会加一次addListMapRefNum
        //这里感觉没有完全统一起来。后续可以都加addListMapRefNum，然后exp转移之前，也是否一次。
        //统一了，都要加。

        addListMapRefNum(pData);
    }
        break;

    case isLower_Fun:
    {
        exprRet->type = EXPR_BOOL;
        exprRet->value.vbool = pBytes->isLower();

    }
    break;


    case isUpper_Fun:
    {
        exprRet->type = EXPR_BOOL;
        exprRet->value.vbool = pBytes->isUpper();

    }
    break;

    case zfc_size_Fun:
    {
        exprRet->type = EXPR_INT;
        exprRet->value.vint = pBytes->size();
    }
    break;

    case compare_Fun:
    case zfc_indexOf_Fun:
    case zfc_lastIndexOf_Fun:
    {
        --lastIndex; //第一个参数

        ExprValue* paraCs = callFunStack->at(lastIndex);

        --lastIndex;
        ExprValue* paraBytes = callFunStack->at(lastIndex);

        exprRet->type = EXPR_INT;

        switch (fun_info->fun_id)
        {
            case compare_Fun:
            {
                if (nullptr != paraBytes->value.vpoint)
                {
                    QByteArray* pSrc = (QByteArray*)paraBytes->value.vpoint;

                    exprRet->value.vint = pBytes->compare(*pSrc, (Qt::CaseSensitivity)paraCs->value.vint);
                }
                else if (pBytes->size() == 0) //都是空
                {
                    //如果都是空，咋办，认定相等。
                    exprRet->value.vint = 0;
                }
                else
                {
                    //原始不为空，原始大。
                    exprRet->type = 0;
                    exprRet->value.vint = 1;
                }
            }
            break;

            case zfc_indexOf_Fun:
            {
                if (paraBytes->type == EXPR_STRING)
                {
                    if (nullptr != paraBytes->value.vpoint)
                    {
                        QByteArray* pSrc = (QByteArray*)paraBytes->value.vpoint;

                        exprRet->value.vint = pBytes->indexOf(*pSrc, paraCs->value.vint);
                    }
                    else
                    {
                        //其余一律认定没有
                        exprRet->value.vint = -1;
                    }
                }
                else if (paraBytes->type == EXPR_CHAR)
                {
                    exprRet->value.vint = pBytes->indexOf(paraBytes->value.vchar, paraCs->value.vint);
                }

            }
            break;

            case zfc_lastIndexOf_Fun:
            {
                if (paraBytes->type == EXPR_STRING)
                {
                    if (nullptr != paraBytes->value.vpoint)
                    {
                        QByteArray* pSrc = (QByteArray*)paraBytes->value.vpoint;

                        exprRet->value.vint = pBytes->lastIndexOf(*pSrc, paraCs->value.vint);
                    }
                    else
                    {
                        //其余一律认定没有
                        exprRet->value.vint = -1;
                    }
                }
                else if (paraBytes->type == EXPR_CHAR)
                {
                    exprRet->value.vint = pBytes->lastIndexOf(paraBytes->value.vchar, paraCs->value.vint);
                }

            }
            break;
        }
    }
    break;

    case zfc_insert_Fun:
    {
        --lastIndex; //第一个参数

        ExprValue* insertStr = callFunStack->at(lastIndex);

        --lastIndex;
        ExprValue* pos = callFunStack->at(lastIndex);

        exprRet->type = EXPR_STRING;

        isNeedRetValue = false;

        if (insertStr->type == EXPR_STRING)
        {
            if (nullptr != insertStr->value.vpoint)
            {
                QByteArray* pSrc = (QByteArray*)insertStr->value.vpoint;

                pBytes->insert(pos->value.vint, *pSrc);

                //exprRet->value.vpoint = new QByteArray(*pBytes);
            }
        }
        else if (insertStr->type == EXPR_CHAR)
        {
             pBytes->insert(pos->value.vint, insertStr->value.vchar);

             //exprRet->value.vpoint = new QByteArray(*pBytes);
        }

    }
    break;

    case zfc_clear_Fun:
    {
        isNeedRetValue = false;
        pBytes->clear();
    }
    break;

    }

    if(hasError != 0)
    {

        ExprValue* funName = callFunStack->last();

        std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();
        int lastIndex = callFunStack->size() - 1;
        ExprValue* obj = callFunStack->at(--lastIndex);

        switch (hasError)
        {
            case 1:
            {
                QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 的参数只能整数类型，请检查！").arg(curLine).arg(curStatement).arg(QStr(name));
                AbortException(msg);
            }
            break;
            case 2:
            {
                QString msg = QString(u8"错误：行号 %1 函数 %2 语句 %3 类名 %4 调用全局函数 %5 错误，字符串类型名只能是 zfc ！").arg(curLine).arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(*obj->varName)).arg(QStr(name));
                AbortException(msg);
            }
            break;
        }

    }

    if (isNeedRetValue)
    {
        callFunStack->push_back(exprRet);
    }
    else
    {
        delete exprRet;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
    }

    return 0;
}

//字符串的内部函数功能
void initStringFunTab()
{

    if (!s_string_fun_sys_load)
    {
       s_string_fun_sys_load = true;

       s_register_call_back_fun = string_fun_cpp;
       s_register_pack_id = EXPR_STRING;

       register_cpp_fun(zfc_append_Fun,"zfc_append",{EXPR_STRING});

       register_cpp_fun(zfc_at_Fun,"zfc_at",{EXPR_INT});

       register_cpp_fun(zfc_back_Fun,"back",{});

       register_cpp_fun(zfc_front_Fun, "front", {});

       register_cpp_fun(chop_Fun,"chop",{EXPR_INT});

       register_cpp_fun(chopped_Fun,"chopped",{EXPR_INT});

       register_cpp_fun(zfc_clear_Fun,"zfc_clear",{});

       register_cpp_fun(zfc_size_Fun,"zfc_size",{});

        //第一次加入，后续可以加1个可选的Int参数。参数检查的时候，做特别判断。只能是最后一个参数时可选的，而且只能有1个。
        //倒数第二个值，是默认参数缺省的默认值。
       register_cpp_fun(compare_Fun, "compare", { EXPR_STRING, 1, EXPR_INT_OPTION});

       register_cpp_fun(zfc_contains_Fun, "zfc_contains", { EXPR_STRING });

       register_cpp_fun(zfc_count_Fun, "zfc_count", { EXPR_STRING });

       register_cpp_fun(endsWith_Fun, "endsWith", { EXPR_STRING });

       register_cpp_fun(startsWith_Fun, "startsWith", { EXPR_STRING });

       register_cpp_fun(zfc_indexOf_Fun, "zfc_indexOf", { EXPR_STRING, 0, EXPR_INT_OPTION });

       register_cpp_fun(zfc_lastIndexOf_Fun, "zfc_lastIndexOf", { EXPR_STRING, -1, EXPR_INT_OPTION });

       register_cpp_fun(zfc_insert_Fun, "zfc_insert", {EXPR_INT, EXPR_STRING });

       register_cpp_fun(zfc_isEmpty_Fun, "zfc_isEmpty", {});

       register_cpp_fun(isLower_Fun, "isLower", {});

       register_cpp_fun(isUpper_Fun, "isUpper", {});

       register_cpp_fun(zfc_left_Fun, "zfc_left", { EXPR_INT });

       register_cpp_fun(zfc_right_Fun, "zfc_right", { EXPR_INT });

       register_cpp_fun(leftJustified_Fun, "leftJustified", { EXPR_INT , EXPR_CHAR, 0, EXPR_INT_OPTION });

       register_cpp_fun(rightJustified_Fun, "rightJustified", { EXPR_INT , EXPR_CHAR, 0, EXPR_INT_OPTION });


       register_cpp_fun(zfc_mid_Fun, "zfc_mid", { EXPR_INT, -1, EXPR_INT_OPTION });

       register_cpp_fun(zfc_push_back_Fun, "zfc_push_back", { EXPR_STRING });

       register_cpp_fun(zfc_push_front_Fun, "zfc_push_front", { EXPR_STRING });

       register_cpp_fun(zfc_remove_Fun, "zfc_remove", { EXPR_INT,EXPR_INT });

       //第一次引入动态参数。参数个数是2到4个。
       register_cpp_fun(zfc_replace_Fun, "zfc_replace", { 2,4,EXPR_PARA_DYNANIC });

       //register_cpp_fun(zfc_setNum_Fun, "zfc_setNum", { 1,3,EXPR_PARA_DYNANIC });

       register_cpp_fun(zfc_create_Fun, "zfc::create", { EXPR_INT,EXPR_CHAR },PACKET_GLOBAL_FUN);



       register_cpp_fun(simplified_Fun, "simplified", {});

       register_cpp_fun(zfc_split_Fun, "zfc_split", { 1,1,EXPR_PARA_DYNANIC});


       register_cpp_fun(toBase64_Fun, "toBase64", { 0, EXPR_INT_OPTION });

       register_cpp_fun(toDouble_Fun, "toDouble", { });

       register_cpp_fun(toFloat_Fun, "toFloat", { });

       register_cpp_fun(toHex_Fun, "toHex", { 0,1,EXPR_PARA_DYNANIC });

       register_cpp_fun(toInt_Fun, "toInt", { 10, EXPR_INT_OPTION });

       register_cpp_fun(toLongLong_Fun, "toLongLong", { 10, EXPR_INT_OPTION });

       register_cpp_fun(toLower_Fun, "toLower", { });

       register_cpp_fun(toUpper_Fun, "toUpper", { });

       register_cpp_fun(trimmed_Fun, "trimmed", { });

       register_cpp_fun(truncate_Fun, "truncate", { EXPR_INT });

       register_cpp_fun(setPosChar_Fun, "setPosChar", { EXPR_INT,EXPR_CHAR });

       register_cpp_fun(zfc_number_Fun, "zfc::number", { 1,3, EXPR_PARA_DYNANIC },PACKET_GLOBAL_FUN);

       register_cpp_fun(zfc_fromBase64_Fun, "zfc::fromBase64", { EXPR_STRING, 0, EXPR_INT_OPTION },PACKET_GLOBAL_FUN);

       register_cpp_fun(zfc_fromHex_Fun, "zfc::fromHex", { EXPR_STRING }, PACKET_GLOBAL_FUN);

       //8字节的double数，以字节保存为16进制的字符hex。反序列荼毒这个hex，生成数组的字符串。
       register_cpp_fun(zfc_fromDoubleHex_Fun, "zfc::fromDoubleHex", { EXPR_STRING,0,EXPR_INT_OPTION }, PACKET_GLOBAL_FUN);

       register_cpp_fun(zfc_fromIntHex_Fun, "zfc::fromIntHex", { EXPR_STRING,0,EXPR_INT_OPTION }, PACKET_GLOBAL_FUN);

       register_cpp_fun(zfc_reverse_Fun, "reverse", { });

       register_cpp_fun(static_zfc_reverse_Fun, "zfc::reverse", { EXPR_STRING }, PACKET_GLOBAL_FUN);

       register_cpp_fun(checksum_Fun, "zfc::checksum", { EXPR_STRING ,0,EXPR_INT_OPTION},PACKET_GLOBAL_FUN);

       register_cpp_fun(compress_Fun, "zfc::compress", { EXPR_STRING ,-1,EXPR_INT_OPTION},PACKET_GLOBAL_FUN);

       register_cpp_fun(uncompress_Fun, "zfc::uncompress", { EXPR_STRING},PACKET_GLOBAL_FUN);

       //目标编码 原始编码默认是Utf8
       register_cpp_fun(zfc_transCode_Fun, "transCode", { EXPR_INT, UTF8_NOBOM, EXPR_INT_OPTION});



    }
}

void initDateFunTab()
{
    if (!s_date_fun_sys_load)
    {
        s_date_fun_sys_load = true;

        s_register_call_back_fun = qdate_fun_cpp;
        s_register_pack_id = EXPR_DATE;

        register_cpp_fun(currentDateTime_Fun, "currentDateTime", {},PACKET_GLOBAL_FUN);
        register_cpp_fun(now_Fun, "now", {},PACKET_GLOBAL_FUN);

        register_cpp_fun(addDays_Fun, "addDays", {EXPR_INT64});


        register_cpp_fun(addMSecs_Fun, "addMSecs", { EXPR_INT64 });


        register_cpp_fun(addMonths_Fun, "addMonths", { EXPR_INT });


        register_cpp_fun(addSecs_Fun, "addSecs", { EXPR_INT64 });


        register_cpp_fun(addYears_Fun, "addYears", { EXPR_INT });


        register_cpp_fun(date_Fun, "date", {});


        register_cpp_fun(daysTo_Fun, "daysTo", {EXPR_DATE});


        register_cpp_fun(secsTo_Fun, "secsTo", { EXPR_DATE });


        register_cpp_fun(msecsTo_Fun, "msecsTo", { EXPR_DATE });


        register_cpp_fun(isValid_Fun, "sj_isValid", {});


        register_cpp_fun(isNull_Fun, "isNull", {});


        register_cpp_fun(offsetFromUtc_Fun, "offsetFromUtc", {});


        register_cpp_fun(setDate_Fun, "setDate", { EXPR_STRING});


        register_cpp_fun(setMSecsSinceEpoch_Fun, "setMSecsSinceEpoch", { EXPR_INT64 });


        register_cpp_fun(setOffsetFromUtc_Fun, "setOffsetFromUtc", { EXPR_INT });


        register_cpp_fun(setSecsSinceEpoch_Fun, "setSecsSinceEpoch", { EXPR_INT64 });


        register_cpp_fun(setTime_Fun, "setTime", { EXPR_STRING });


        register_cpp_fun(time_Fun, "time", { });


        register_cpp_fun(toLocalTime_Fun, "toLocalTime", { });


        register_cpp_fun(toMSecsSinceEpoch_Fun, "toMSecsSinceEpoch", { });


        register_cpp_fun(toOffsetFromUtc_Fun, "toOffsetFromUtc", { EXPR_INT });


        register_cpp_fun(toSecsSinceEpoch_Fun, "toSecsSinceEpoch", { });


        register_cpp_fun(toString_Fun, "sj_toString", { EXPR_STRING });

        register_cpp_fun(getDateString_Fun, "getDateString", {  });
        register_cpp_fun(getTimeString_Fun, "getTimeString", {  });





        register_cpp_fun(toUTC_Fun, "toUTC", { });


        register_cpp_fun(fromString_Fun, "fromString", { EXPR_STRING,EXPR_STRING},PACKET_GLOBAL_FUN);


        register_cpp_fun(msleep_Fun, "msleep", { EXPR_INT},PACKET_GLOBAL_FUN);


        register_cpp_fun(sleep_Fun, "sleep", { EXPR_INT},PACKET_GLOBAL_FUN);





        /*
            ,
            setTimeSpec_Fun,
            setTimeZone_Fun,
            time_Fun,
            timeSpec_Fun,
            timeZone_Fun,
            timeZoneAbbreviation_Fun,
            toLocalTime_Fun,
            toMSecsSinceEpoch_Fun,
            toOffsetFromUtc_Fun,
            toSecsSinceEpoch_Fun,
            toString_Fun,
            toTimeSpec_Fun,
            toTimeZone_Fun,
            toUTC_Fun,
            */
    }
}

void initCppFunTab()
{
    if(s_cppFunTab == nullptr)
    {
        s_cppFunTab = new std::unordered_map<std::string, CPP_FUN_INFO*>();
#ifdef PIN_MEM_REF
        newTime();
#endif
        initPinFunTab();
    }
}


//-1 错误，必须要退出不能继续查找。 1 成功找到api 其余继续查找。
int findApiByName(std::string & funName, ExprValue& objExpr, CPP_FUN_INFO* & retOut)
{
    auto it = s_cppFunTab->find(funName);

    //如果存在，而且调用者的类型可以匹配。
    if (it != s_cppFunTab->end())
    {
        int dstType = it->second->fun_type;


        //如果是全局包函数调用，必须是全局函数才行
        if (objExpr.type == EXPR_GLOBAL_PACKNAME && (dstType != PACKET_GLOBAL_FUN && dstType != EXPR_ALL_PACK_FUN))
        {
            //报错。找到了函数，但是目标函数不是全局包可以匹配的函数，直接报错。
            return -1;
        }

        int type = (objExpr.type != EXPR_GLOBAL_PACKNAME) ? objExpr.type : objExpr.value.vpacktype;

        //如果不是结构体，则只需要对比类型即可。
        if (type != EXPR_STRUCT && (it->second->owner_pack_id == type || dstType == EXPR_ALL_PACK_FUN))
        {
            retOut = it->second;
            return 1;
        }
        //是结构体，还要比较结构体类型。
        if (type == EXPR_STRUCT && (it->second->owner_pack_id == objExpr.getStructTypeId() || dstType == EXPR_ALL_PACK_FUN))
        {
            retOut = it->second;
            return 1;
        }
    }

    return -2;
}

///objType 类型名称，比如 FILE_ID LIST_ID MAP_ID, funName就是函数名称
CPP_FUN_INFO* findCppFun(ExprValue& objExpr, std::string& funName, PinParser::RealCallFunContext* ctx)
{
    int type = objExpr.type;

    //std::unordered_map<std::string, CPP_FUN_INFO*>::iterator it;

    //如果是全局方法，即调研wj::xxx的格式，优先使用::格式。
    if (objExpr.type == EXPR_GLOBAL_PACKNAME)
    {
        //目前有文件、字符串，优先使用。后续有其它再加
        if(objExpr.value.vpacktype == EXPR_FILE)
        {
            if (!s_file_fun_sys_load)
            {
                initFileFunTab();
            }

            auto it = s_cppFunTab->find("wj::" + funName);

            if (it != s_cppFunTab->end())
            {
                //如果不是结构体，则只需要对比类型即可。
                    if ((it->second->owner_pack_id == objExpr.value.vpacktype || it->second->fun_type == EXPR_ALL_PACK_FUN))
                {
                    return it->second;
                }
            }
        }
        else if (objExpr.value.vpacktype == EXPR_STRING)
        {
            if (!s_string_fun_sys_load)
            {
                initStringFunTab();
            }

            auto it = s_cppFunTab->find("zfc::" + funName);

            if (it != s_cppFunTab->end())
            {
                //如果不是结构体，则只需要对比类型即可。
                if ((it->second->owner_pack_id == objExpr.value.vpacktype || it->second->fun_type == EXPR_ALL_PACK_FUN))
                {
                    return it->second;
                }
            }
        }

        //如果没找到，则只能查找适合所有包都能使用的方法，目前就是desc了。不能继续查找或调用结构体的成员方法，二者不能混用。
        //为了灵活，每个类型的处理路径不一样。目前文件就是严格查询全局或desc，其余不能使用。
        type = objExpr.value.vpacktype;
    }

    CPP_FUN_INFO* retOut = nullptr;
    int retcode = 0;

    //U16字符串因为和 QBYTEARRRY方法同名，所以无条件加包名
    if (type == EXPR_U16STRING)
    {
        std::string key = "qstr_" + funName;
        retcode = findApiByName(key, objExpr,retOut);
    }
    else
    {
        retcode = findApiByName(funName, objExpr,retOut);
    }

    if(retcode == 1)
    {
        return retOut;
    }
    else if(retcode == -1)
    {
        goto out_err;
    }


#if 0
    //如果存在，而且调用者的类型可以匹配。
    if (it != s_cppFunTab->end())
    {
        int dstType = it->second->fun_type;

        //如果是全局包函数调用，必须是全局函数才行
        if (objExpr.type == EXPR_GLOBAL_PACKNAME && (dstType != PACKET_GLOBAL_FUN && dstType != EXPR_ALL_PACK_FUN))
        {
            //报错。找到了函数，但是目标函数不是全局包可以匹配的函数，直接报错。
            goto out_err;
        }

        //如果不是结构体，则只需要对比类型即可。
        if (type != EXPR_STRUCT && (it->second->owner_pack_id == type || dstType == EXPR_ALL_PACK_FUN))
        {
            return it->second;
        }
        //是结构体，还要比较结构体类型。
        if (type == EXPR_STRUCT && (it->second->owner_pack_id == objExpr.getStructTypeId() || dstType == EXPR_ALL_PACK_FUN))
        {
            return it->second;
        }
    }
#endif

    //没有找到或没能匹配。
    if (type != EXPR_ERR)
    {
        bool delayTry = false;
        std::string baoName;
        //没有找到，来一次延迟加载查找
        switch (type)
        {
        case EXPR_FILE:
        {
            if (!s_file_fun_sys_load)
            {
                initFileFunTab();
                delayTry = true;
            }
            baoName = "wj_";

        }
        break;

        case EXPR_EXCEL:
        {
            if (!s_excel_fun_sys_load)
            {
                initExcelFunTab();
                delayTry = true;
            }
            baoName = "el_";

        }
        break;

        case EXPR_DATE:
        {
            if (!s_date_fun_sys_load)
            {
                initDateFunTab();
                delayTry = true;
            }
            baoName = "sj_";
        }
        break;

        case EXPR_STRING:
        {
            if (!s_string_fun_sys_load)
            {
                initStringFunTab();
                delayTry = true;
            }
            baoName = "zfc_";
        }
        break;

        case EXPR_U16STRING:
        {
            if (!s_qstring_fun_sys_load)
            {
                initQStringFunTab();
                delayTry = true;
            }
            baoName = "qstr_";
        }
        break;

        case EXPR_WCHAR:
        {
            if (!s_qchar_fun_sys_load)
            {
                initQCharFunTab();
                delayTry = true;
            }
            baoName = "qchr_";
        }
        break;

        case EXPR_CHAR:
        {
            if (!s_char_fun_sys_load)
            {
                initCharFunTab();
                delayTry = true;
            }
            baoName = "zf_";
        }
        break;

        case EXPR_LIST:
        {
            if (!s_list_fun_sys_load)
            {
                initListFunTab();
                delayTry = true;
            }
            baoName = "lb_";
        }
        break;

        case EXPR_MAP:
        {
            if (!s_map_fun_sys_load)
            {
                initMapFunTab();
                delayTry = true;
            }
            baoName = "zd_";
        }
        break;



        //目前只有表格结构体XLWorksheet,其它都没
        case EXPR_STRUCT:
        {

            switch (objExpr.getStructTypeId())
            {
            case XLWorksheet_Struct_ID:
            {
                baoName = "xws_";

                if (!s_excel_fun_sys_load)
                {
                    initExcelFunTab();
                    delayTry = true;
                }
            }
            break;

            case REGEXP_Struct_ID:
            {
                if (!s_regexp_sys_load)
                {
                    initRegExpFunTab();
                    delayTry = true;
                }
                baoName = "reg_";
            }
                break;

            case REGMATCH_Struct_ID:
            case REGMATCH_ITER_Struct_ID:
            {
                if (!s_regexp_sys_load)
                {
                    initRegExpFunTab();
                    delayTry = true;
                }
                baoName = "mat_";
            }
                break;

#ifdef NDD_PIN_FUN
            case NddMainWin_Struct_ID:
            case Editor_Struct_ID:
            {
                if (!s_ndd_fun_sys_load)
                {
                    initNddFunTab();
                    delayTry = true;
                }
                baoName = "ndd_";
            }
            break;
#endif

            default:
            {
                baoName = "pin_";
            }
            }
            //结构体有些特殊，结构体可以有自己底层的内部方法。也可以调用默认的desc方法。咋办。
        }
        break;

        //这个EXPR_PIN没有对象实例，目前只有pin报名，使用pin.xxx 进行访问。
        case EXPR_PIN:
        {
            //pin是无条件加载的，没有延迟的说法。
            baoName = "pin_";
        }
        break;
#ifdef NDD_PIN_FUN
        case EXPR_NDD:
        {
            if (!s_ndd_fun_sys_load)
            {
                initNddFunTab();
                delayTry = true;
            }
            baoName = "ndd_";
        }
        break;
#endif

        default:
        {
            //其余所有的，目前都走pin即可。比如desc函数，每个对象都有。
            baoName = "pin_";

        }
        break;

        }

        //是延长加载了，则再来一次。
        if (delayTry)
        {

            retcode = findApiByName(funName, objExpr,retOut);

            if(retcode == 1)
            {
                return retOut;
            }
            else if(retcode == -1)
            {
                goto out_err;
            }

#if 0
            it = s_cppFunTab->find(funName);

            //如果存在，而且调用者的类型可以匹配。
            if (it != s_cppFunTab->end())
            {
                //如果是全局包函数调用，必须是全局函数才行
                if (objExpr.type == EXPR_GLOBAL_PACKNAME && (dstType != PACKET_GLOBAL_FUN && dstType != EXPR_ALL_PACK_FUN))
                {
                    //报错。找到了函数，但是目标函数不是全局包可以匹配的函数，直接报错。
                    goto out_err;
                }

                //如果不是结构体，则只需要对比类型即可。
                if (type != EXPR_STRUCT && (it->second->owner_pack_id == type || it->second->fun_type == EXPR_ALL_PACK_FUN))
                {
                    return it->second;
                }
                //是结构体，还要比较结构体类型。
                if (type == EXPR_STRUCT && (it->second->owner_pack_id == objExpr.getStructTypeId() || it->second->fun_type == EXPR_ALL_PACK_FUN))
                {
                    return it->second;
                }
            }
#endif
        }
#if 0
        //还是没有，使用包名+funName全称查找。
        it = s_cppFunTab->find(baoName + funName);

        if (it != s_cppFunTab->end())
        {
            //如果是全局包函数调用，必须是全局函数才行
            if (objExpr.type == EXPR_GLOBAL_PACKNAME && (dstType != PACKET_GLOBAL_FUN && dstType != EXPR_ALL_PACK_FUN))
            {
                //报错。找到了函数，但是目标函数不是全局包可以匹配的函数，直接报错。
                goto out_err;
            }

            return it->second;
        }
#endif

        std::string key = baoName + funName;
        retcode = findApiByName(key, objExpr,retOut);

        if(retcode == 1)
        {
            return retOut;
    }

    }

out_err:
    if (ctx != nullptr)
    {
        QString msg = QString(u8"错误：行号：%1 语句 %2 调用变量或表达式 %3 值是 %4 ，该类型没有函数 %5\n调用对象的函数 %5不存在，请查看手册或检查拼写错误！").arg(curLine).arg(curStatement)
            .arg(QStr(*objExpr.varName)).arg(getExpeTypeValue(objExpr.type, &objExpr) /*getVarTypeNameByName(*objExpr.varName, ctx)*/).arg(QStr(funName));

        //如果是函数，把函数的位置打印出来，避免找不到。
        if (objExpr.type == EXPR_FUN)
        {
            FUN_SYM_INFO* pSym = findFunBlock(*objExpr.varName);
            if (pSym != nullptr)
            {
                QString funMsg = QString(u8"见函数 %1 的定义：行 %2 %3").arg(QStr(*objExpr.varName)).arg(pSym->funNameLineNum).arg(QStr(pSym->funDec));
                msg += "\n" + funMsg;
            }
        }
        AbortException(msg);
    }
    else
    {
        QString msg = QString(u8"错误：变量 %1 是 %2 ，该类型没有函数 %3").arg(QStr(*objExpr.varName)).arg(getExpeTypeValue(type)).arg(QStr(funName));
        AbortException(msg);
    }

    return nullptr;
}

void destoryCppFunTab()
{
    if(s_cppFunTab != nullptr)
    {
        for (std::unordered_map<std::string, CPP_FUN_INFO*>::iterator it = s_cppFunTab->begin(); it != s_cppFunTab->end(); ++it)
        {
            it->second->destory();
            delete it->second;
#ifdef PIN_MEM_REF
            freeTimes++;
#endif
        }

        delete s_cppFunTab;
#ifdef PIN_MEM_REF
        freeTimes++;
#endif
        s_cppFunTab = nullptr;
    }
}



void checkCallFunPara(PinParser::RealCallFunContext* ctx, std::string& funName, CPP_FUN_INFO& funInfo)
{
    QList<ExprValue*>* callFunStack = getFunCallStack();

    std::vector<int>* paraList = funInfo.paraList;

    //参数 + 对象+函数名称，所以要多2个
    if(paraList == nullptr && callFunStack->size() == 2)
    {
        //没有参数。
    }
    else if (paraList != nullptr && (EXPR_PARA_DYNANIC == paraList->at(paraList->size() - 1)))
    {
        //如果是动态参数，则直接检查参数个数，不检查参数类型，延迟再检查。
        int paraNum = callFunStack->size() - 2;

        if (paraNum > paraList->at(1) && paraNum < paraList->at(0))
        {

            QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 参数个数错误，没有可以匹配该调用形式的参数个数！").arg(curLine).arg(curStatement).arg(QStr(funName));
            AbortException(msg);
        }
    }
    else if(paraList->size() == (callFunStack->size() - 2))
    {
        //参数格式相等，再进一步检查每个参数的类型
        for(int i=0,c = paraList->size(); i<c; ++i)
        {
            if(exprTypeMatch(paraList->at(i),callFunStack->at(i)->type,false,true,callFunStack->at(i)) < 0)
            {

                QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 第 %4 个参数无法匹配，第 %4 个参数需要是%5, 给定参数是%6！").arg(curLine).arg(curStatement).arg(QStr(funName)).arg(i+1).arg(getExpeTypeValue(paraList->at(i))).arg(getExpeTypeValue(callFunStack->at(i)->type));
                AbortException(msg);
                break;
            }
        }
    }
    else if ((paraList->size() == (callFunStack->size()-1)) && (EXPR_INT_OPTION == paraList->at(paraList->size() - 1)))
    {

        //如果给定参数少了1项，前面调用函数时，已经自动加入1项了。那么判断最后的可选参数情况。
        //最后一个参数。必须是可选EXPR_INT_OPTION类型，目前暂时只支持这种。

       //少了一个参数，那么最后一个参数必须是可选的才行。详细检查。
        for (int i=0,c = paraList->size()-2; i < c; ++i)
        {
            if (exprTypeMatch(paraList->at(i), callFunStack->at(i)->type,false,true,callFunStack->at(i)) < 0)
            {

                QString msg = QString(u8"错误：函数 %1 语句 %2 调用函数 %3 第 %4 个参数无法匹配！").arg(getCurFunQSName()).arg(curStatement).arg(QStr(funName)).arg(i + 1);
                AbortException(msg);
                break;
            }
        }
    }
    else
    {

        QString msg = QString(u8"错误：行号 %1 语句 %2 调用函数 %3 参数个数无法匹配").arg(curLine).arg(curStatement).arg(QStr(funName));
        AbortException(msg);
    }
}

//参数1 参数2 对象 函数名称。没有对象也塞入一个空对象
void callFun(CPP_FUN_INFO* s_cppFunTab, PinParser::RealCallFunContext* ctx)
{
    //QList<ExprValue*>* callFunStack = getFunCallStack();

    //最少2个参数，对象、名称。永远不会执行
   /* if (callFunStack->size() < 2)
    {
        QString msg = QString(u8"错误：函数 %1 语句 %2 变量 %3 内部函数调用参数格式错误，参数为0 ！").arg(getCurFunQSName()).arg(QStr(ctx->getText())).arg(QStr(ctx->memberFunAccess()->funobj()->getText()));
        AbortException(msg);
        return;
    }*/

    //把参数检查拿到外面去检查，提取报错。
    /*
    ExprValue* funName = callFunStack->last();

    std::string name = ((QByteArray*)funName->value.vpoint)->toStdString();

    //一定先检查参数是否能够匹配，后续则放开去调用即可。
    checkCallFunPara(ctx,name, *s_cppFunTab);
*/

        //执行对应的cpp回调函数即可。
    s_cppFunTab->call_back_fun(s_cppFunTab, ctx);

}

//全局pin包名对应的方法。没有对象，只有包名方法。
void initPinFunTab()
{
    if (!s_pin_fun_sys_load)
    {
        s_pin_fun_sys_load = true;


        s_register_call_back_fun = pin_fun_cpp;
        s_register_pack_id = EXPR_PIN;

        register_cpp_fun(pin_exec_Fun, "exec", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(pin_exec_output_Fun, "exec_output", { EXPR_STRING },PACKET_GLOBAL_FUN);

        register_cpp_fun(pin_line_Fun, "line", { },PACKET_GLOBAL_FUN);

        register_cpp_fun(pin_fun_Fun, "fun", { },PACKET_GLOBAL_FUN);

        register_cpp_fun(pin_yield_Fun, "yield", { },PACKET_GLOBAL_FUN);

        register_cpp_fun(pin_exit_Fun, "exit", { 0,EXPR_INT_OPTION },PACKET_GLOBAL_FUN);

        register_cpp_fun(pin_getopt_Fun, "getopt", {EXPR_LIST,EXPR_STRING,EXPR_LIST },PACKET_GLOBAL_FUN);

        //s_register_pack_id = EXPR_ALL_PACK_FUN;

        register_cpp_fun(pin_desc_Fun, "desc", { },EXPR_ALL_PACK_FUN);


    }
}
